aiobungie
A Pythonic async/await wrapper for interacting with the Bungie API.
Base client.
Example
import aiobungie
client = aiobungie.Client('YOUR_API_KEY')
# Search for Destiny2 users.
async def main() -> None:
users = await client.search_users('Crit')
# Iterate over the users and take the first 5 results.
for user in users.take(5):
print(f'{user.name} ({user.code})')
# Iterate through the users memberships.
for membership in user.memberships:
print(membership.type, membership.id)
client.run(main()) # or asyncio.run(main())
Single RESTClient instance.
The difference between base client and the REST clients:
- No Hight-Level concepts.
- All returned data are pure JSON objects from the API.
- No object creation.
Example
import aiobungie
async def main() -> None:
# Using `async with` context manager to close the session properly.
async with aiobungie.RESTClient("TOKEN") as rest:
payload = await rest.fetch_player('Fate怒', 4275)
for membership in payload:
print(membership['membershipId'], membership['iconPath'])
import asyncio
asyncio.run(main())
REST client pool.
A REST client pool allows you to acquire multiple RESTClient instances that shares the same connection.
Example
import aiobungie
import asyncio
pool = aiobungie.RESTPool("token")
async def func1() -> None:
async with pool.acquire() as instance:
tokens = await instance.fetch_oauth2_tokens('code')
pool.metadata['tokens'] = tokens
# Other instance may access the tokens from pool since its shared.
async def func2() -> None:
async with pool.acquire() as instance:
tokens = pool.metadata['tokens']
tokens = await instance.refresh_access_token(tokens.refresh_token)
async def main() -> None:
await asyncio.gather(func1(), func2())
asyncio.run(main())
Should you use the base client or the REST client? This returns to you. For an example if you're building a website.
You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. Which gives you the freedom to deserialize it and implement your own logic in the front-end.
Or of you're building a Discord bot for an example or something simple. The base client is the way to go.
1# MIT License 2# 3# Copyright (c) 2020 - Present nxtlo 4# 5# Permission is hereby granted, free of charge, to any person obtaining a copy 6# of this software and associated documentation files (the "Software"), to deal 7# in the Software without restriction, including without limitation the rights 8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9# copies of the Software, and to permit persons to whom the Software is 10# furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice shall be included in all 13# copies or substantial portions of the Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21# SOFTWARE. 22 23"""A Pythonic `async`/`await` wrapper for interacting with the Bungie API. 24 25Base client. 26 27Example 28------- 29```py 30import aiobungie 31 32client = aiobungie.Client('YOUR_API_KEY') 33 34# Search for Destiny2 users. 35async def main() -> None: 36 users = await client.search_users('Crit') 37 38 # Iterate over the users and take the first 5 results. 39 for user in users.take(5): 40 print(f'{user.name} ({user.code})') 41 42 # Iterate through the users memberships. 43 for membership in user.memberships: 44 print(membership.type, membership.id) 45 46client.run(main()) # or asyncio.run(main()) 47``` 48 49Single RESTClient instance. 50 51The difference between base client and the REST clients: 52 53* No Hight-Level concepts. 54* All returned data are pure JSON objects from the API. 55* No object creation. 56 57Example 58------- 59```py 60import aiobungie 61 62async def main() -> None: 63 # Using `async with` context manager to close the session properly. 64 async with aiobungie.RESTClient("TOKEN") as rest: 65 payload = await rest.fetch_player('Fate怒', 4275) 66 67 for membership in payload: 68 print(membership['membershipId'], membership['iconPath']) 69 70import asyncio 71asyncio.run(main()) 72``` 73 74REST client pool. 75 76A REST client pool allows you to acquire multiple `RESTClient` instances that shares the same connection. 77 78Example 79------- 80```py 81import aiobungie 82import asyncio 83 84pool = aiobungie.RESTPool("token") 85 86async def func1() -> None: 87 async with pool.acquire() as instance: 88 tokens = await instance.fetch_oauth2_tokens('code') 89 pool.metadata['tokens'] = tokens 90 91# Other instance may access the tokens from pool since its shared. 92 93async def func2() -> None: 94 async with pool.acquire() as instance: 95 tokens = pool.metadata['tokens'] 96 tokens = await instance.refresh_access_token(tokens.refresh_token) 97 98async def main() -> None: 99 await asyncio.gather(func1(), func2()) 100 101asyncio.run(main()) 102``` 103 104Should you use the base client or the REST client? 105This returns to you. For an example if you're building a website. 106 107You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. 108Which gives you the freedom to deserialize it and implement your own logic in the front-end. 109 110Or of you're building a Discord bot for an example or something simple. The base client is the way to go. 111""" 112 113 114from __future__ import annotations 115 116from aiobungie import builders 117from aiobungie import crates 118from aiobungie import interfaces 119from aiobungie import traits 120from aiobungie import typedefs 121from aiobungie import url 122from aiobungie.client import Client 123from aiobungie.error import * 124from aiobungie.internal import iterators 125from aiobungie.internal.assets import Image 126from aiobungie.internal.enums import * 127from aiobungie.internal.factory import Factory 128from aiobungie.internal.iterators import * 129from aiobungie.rest import * 130from aiobungie.undefined import Undefined 131from aiobungie.undefined import UndefinedOr 132from aiobungie.undefined import UndefinedType 133 134from ._info import __about__ 135from ._info import __author__ 136from ._info import __docs__ 137from ._info import __email__ 138from ._info import __license__ 139from ._info import __url__ 140from ._info import __version__ 141 142# Alias for crate for backwards compatibility. 143crate = crates 144 145# Activity enums 146from .crates.activity import Difficulty 147 148# Components enums 149from .crates.components import ComponentFields 150from .crates.components import ComponentPrivacy 151 152# Entity enums 153from .crates.entity import GatingScope 154from .crates.entity import ObjectiveUIStyle 155from .crates.entity import ValueUIStyle 156 157# Fireteam enums. 158from .crates.fireteams import FireteamActivity 159from .crates.fireteams import FireteamDate 160from .crates.fireteams import FireteamLanguage 161from .crates.fireteams import FireteamPlatform 162 163# Records enums 164from .crates.records import RecordState 165 166__all__ = [mod for mod in dir() if not mod.startswith("_")] # type: ignore
57@attrs.define(auto_exc=True) 58class AiobungieError(RuntimeError): 59 """Base exception class that all other errors inherit from."""
Base exception class that all other errors inherit from.
Inherited Members
- builtins.BaseException
- with_traceback
- args
646@typing.final 647class AmmoType(int, Enum): 648 """AN enum for Detyiny 2 ammo types.""" 649 650 NONE = 0 651 PRIMARY = 1 652 SPECIAL = 2 653 HEAVY = 3
AN enum for Detyiny 2 ammo types.
147@attrs.define(auto_exc=True) 148class BadRequest(HTTPError): 149 """Bad requests exceptions.""" 150 151 url: typing.Optional[typedefs.StrOrURL] 152 """The URL/endpoint caused this error.""" 153 154 body: typing.Any 155 """The response body.""" 156 157 headers: multidict.CIMultiDictProxy[str] 158 """The response headers.""" 159 160 http_status: http.HTTPStatus = attrs.field(default=http.HTTPStatus.BAD_REQUEST)
Bad requests exceptions.
2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = http_status 8 BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status)
Method generated by attrs for class BadRequest.
701@typing.final 702class ClanMemberType(int, Enum): 703 """An enum for bungie clan member types.""" 704 705 NONE = 0 706 BEGINNER = 1 707 MEMBER = 2 708 ADMIN = 3 709 ACTING_FOUNDER = 4 710 FOUNDER = 5
An enum for bungie clan member types.
477@typing.final 478class Class(int, Enum): 479 """An Enum for Destiny character classes.""" 480 481 TITAN = 0 482 HUNTER = 1 483 WARLOCK = 2 484 UNKNOWN = 3
An Enum for Destiny character classes.
61class Client(traits.ClientApp): 62 """Standard Bungie API client application. 63 64 This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory` 65 and returns `aiobungie.crates` Python object implementations of the responses. 66 67 A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts. 68 69 Parameters 70 ----------- 71 token: `str` 72 Your Bungie's API key or Token from the developer's portal. 73 74 Other Parameters 75 ---------------- 76 rest_client: `aiobungie.interfaces.RESTInterface | None` 77 An optional rest client instance you can pass. 78 If set to `None` then the client will use the default instance. 79 80 max_retries : `int` 81 The max retries number to retry if the request hit a `5xx` status code. 82 max_ratelimit_retries : `int` 83 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 84 client_secret : `str | None` 85 An optional application client secret, 86 This is only needed if you're fetching OAuth2 tokens with this client. 87 client_id : `int | None` 88 An optional application client id, 89 This is only needed if you're fetching OAuth2 tokens with this client. 90 """ 91 92 __slots__ = ("_rest", "_factory", "_client_secret", "_client_id") 93 94 def __init__( 95 self, 96 token: str, 97 /, 98 client_secret: typing.Optional[str] = None, 99 client_id: typing.Optional[int] = None, 100 *, 101 rest_client: typing.Optional[interfaces.RESTInterface] = None, 102 max_retries: int = 4, 103 max_ratelimit_retries: int = 3, 104 ) -> None: 105 106 self._client_secret = client_secret 107 self._client_id = client_id 108 109 self._rest = ( 110 rest_client 111 if rest_client is not None 112 else rest_.RESTClient( 113 token, 114 client_secret, 115 client_id, 116 max_retries=max_retries, 117 max_ratelimit_retries=max_ratelimit_retries, 118 ) 119 ) 120 121 self._factory = factory_.Factory(self) 122 123 @property 124 def factory(self) -> factory_.Factory: 125 return self._factory 126 127 @property 128 def rest(self) -> interfaces.RESTInterface: 129 return self._rest 130 131 @property 132 def request(self) -> Client: 133 return copy.copy(self) 134 135 @property 136 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 137 return self._rest.metadata 138 139 def run( 140 self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False 141 ) -> None: 142 loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop() 143 try: 144 if not loop.is_running(): 145 loop.set_debug(debug) 146 loop.run_until_complete(future) 147 148 except Exception as exc: 149 raise RuntimeError(f"Failed to run {future.__qualname__}") from exc 150 151 except KeyboardInterrupt: 152 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 153 return 154 155 finally: 156 if self._rest.is_alive: 157 # Clean up sessions. 158 loop.run_until_complete(self._rest.close()) 159 160 # * User methods. 161 162 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 163 """Fetch and return a user object of the bungie net user associated with account. 164 165 .. warning:: 166 This method requires OAuth2 scope and a Bearer access token. 167 168 Parameters 169 ---------- 170 access_token : `str` 171 A valid Bearer access token for the authorization. 172 173 Returns 174 ------- 175 `aiobungie.crates.user.User` 176 A user object includes the Destiny memberships and Bungie.net user. 177 """ 178 resp = await self.rest.fetch_current_user_memberships(access_token) 179 180 return self.factory.deserialize_user(resp) 181 182 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 183 """Fetch a Bungie user by their BungieNet id. 184 185 .. note:: 186 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 187 for other memberships. 188 189 Parameters 190 ---------- 191 id: `int` 192 The user id. 193 194 Returns 195 ------- 196 `aiobungie.crates.user.BungieUser` 197 A Bungie user. 198 199 Raises 200 ------ 201 `aiobungie.error.NotFound` 202 The user was not found. 203 """ 204 payload = await self.rest.fetch_bungie_user(id) 205 206 return self.factory.deserialize_bungie_user(payload) 207 208 async def search_users( 209 self, name: str, / 210 ) -> iterators.FlatIterator[user.SearchableDestinyUser]: 211 """Search for players and return all players that matches the same name. 212 213 Parameters 214 ---------- 215 name : `buildins.str` 216 The user name. 217 218 Returns 219 ------- 220 `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]` 221 A sequence of destiny memberships. 222 """ 223 payload = await self.rest.search_users(name) 224 225 return iterators.FlatIterator( 226 [ 227 self.factory.deserialize_searched_user(user) 228 for user in payload["searchResults"] 229 ] 230 ) 231 232 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 233 """Fetch all available user themes. 234 235 Returns 236 ------- 237 `collections.Sequence[aiobungie.crates.user.UserThemes]` 238 A sequence of user themes. 239 """ 240 data = await self.rest.fetch_user_themes() 241 242 return self.factory.deserialize_user_themes(data) 243 244 async def fetch_hard_types( 245 self, 246 credential: int, 247 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 248 /, 249 ) -> user.HardLinkedMembership: 250 """Gets any hard linked membership given a credential. 251 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 252 Cross Save aware. 253 254 Parameters 255 ---------- 256 credential: `int` 257 A valid SteamID64 258 type: `aiobungie.CredentialType` 259 The credential type. This must not be changed 260 Since its only credential that works "currently" 261 262 Returns 263 ------- 264 `aiobungie.crates.user.HardLinkedMembership` 265 Information about the hard linked data. 266 """ 267 268 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 269 270 return user.HardLinkedMembership( 271 id=int(payload["membershipId"]), 272 type=enums.MembershipType(payload["membershipType"]), 273 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 274 ) 275 276 async def fetch_membership_from_id( 277 self, 278 id: int, 279 /, 280 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 281 ) -> user.User: 282 """Fetch Bungie user's memberships from their id. 283 284 Notes 285 ----- 286 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 287 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 288 see `aiobungie.crates.user.DestinyMembership` for more details. 289 * If you only want the bungie user. Consider using `Client.fetch_user` method. 290 291 Parameters 292 ---------- 293 id : `int` 294 The user's id. 295 type : `aiobungie.MembershipType` 296 The user's membership type. 297 298 Returns 299 ------- 300 `aiobungie.crates.User` 301 A Bungie user with their membership types. 302 303 Raises 304 ------ 305 aiobungie.NotFound 306 The requested user was not found. 307 """ 308 payload = await self.rest.fetch_membership_from_id(id, type) 309 310 return self.factory.deserialize_user(payload) 311 312 async def fetch_user_credentials( 313 self, access_token: str, membership_id: int, / 314 ) -> collections.Sequence[user.UserCredentials]: 315 """Fetch an array of credential types attached to the requested account. 316 317 .. note:: 318 This method require OAuth2 Bearer access token. 319 320 Parameters 321 ---------- 322 access_token : `str` 323 The bearer access token associated with the bungie account. 324 membership_id : `int` 325 The id of the membership to return. 326 327 Returns 328 ------- 329 `collections.Sequence[aiobungie.crates.UserCredentials]` 330 A sequence of the attached user credentials. 331 332 Raises 333 ------ 334 `aiobungie.Unauthorized` 335 The access token was wrong or no access token passed. 336 """ 337 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 338 339 return self.factory.deserialize_user_credentials(resp) 340 341 # * Destiny 2. 342 343 async def fetch_profile( 344 self, 345 member_id: int, 346 type: typedefs.IntAnd[enums.MembershipType], 347 components: list[enums.ComponentType], 348 auth: typing.Optional[str] = None, 349 ) -> components.Component: 350 """ 351 Fetch a bungie profile passing components to the request. 352 353 Parameters 354 ---------- 355 member_id: `int` 356 The member's id. 357 type: `aiobungie.MembershipType` 358 A valid membership type. 359 components : `list[aiobungie.ComponentType]` 360 List of profile components to collect and return. 361 362 Other Parameters 363 ---------------- 364 auth : `typing.Optional[str]` 365 A Bearer access_token to make the request with. 366 This is optional and limited to components that only requires an Authorization token. 367 368 Returns 369 -------- 370 `aiobungie.crates.Component` 371 A Destiny 2 player profile with its components. 372 Only passed components will be available if they exists. Otherwise they will be `None` 373 374 Raises 375 ------ 376 `aiobungie.MembershipTypeError` 377 The provided membership type was invalid. 378 """ 379 data = await self.rest.fetch_profile(member_id, type, components, auth) 380 return self.factory.deserialize_components(data) 381 382 async def fetch_linked_profiles( 383 self, 384 member_id: int, 385 member_type: typedefs.IntAnd[enums.MembershipType], 386 /, 387 *, 388 all: bool = False, 389 ) -> profile.LinkedProfile: 390 """Returns a summary information about all profiles linked to the requested member. 391 392 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 393 394 .. note:: 395 It will only return linked accounts whose linkages you are allowed to view. 396 397 Parameters 398 ---------- 399 member_id : `int` 400 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 401 member_type : `aiobungie.MembershipType` 402 The type for the membership whose linked Destiny account you want to return. 403 404 Other Parameters 405 ---------------- 406 all : `bool` 407 If provided and set to `True`, All memberships regardless 408 of whether they're obscured by overrides will be returned, 409 410 If provided and set to `False`, Only available memberships will be returned. 411 The default for this is `False`. 412 413 Returns 414 ------- 415 `aiobungie.crates.profile.LinkedProfile` 416 A linked profile object. 417 """ 418 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 419 420 return self.factory.deserialize_linked_profiles(resp) 421 422 async def fetch_player( 423 self, 424 name: str, 425 code: int, 426 /, 427 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 428 ) -> collections.Sequence[user.DestinyMembership]: 429 """Fetch a Destiny 2 player's memberships. 430 431 Parameters 432 ----------- 433 name: `str` 434 The unique Bungie player name. 435 code : `int` 436 The unique Bungie display name code. 437 type: `aiobungie.internal.enums.MembershipType` 438 The player's membership type, e,g. XBOX, STEAM, PSN 439 440 Returns 441 -------- 442 `collections.Sequence[aiobungie.crates.DestinyMembership]` 443 A sequence of the found Destiny 2 player memberships. 444 An empty sequence will be returned if no one found. 445 446 Raises 447 ------ 448 `aiobungie.MembershipTypeError` 449 The provided membership type was invalid. 450 """ 451 resp = await self.rest.fetch_player(name, code, type) 452 453 return self.factory.deserialize_destiny_memberships(resp) 454 455 async def fetch_character( 456 self, 457 member_id: int, 458 membership_type: typedefs.IntAnd[enums.MembershipType], 459 character_id: int, 460 components: list[enums.ComponentType], 461 auth: typing.Optional[str] = None, 462 ) -> components.CharacterComponent: 463 """Fetch a Destiny 2 character. 464 465 Parameters 466 ---------- 467 member_id: `int` 468 A valid bungie member id. 469 character_id: `int` 470 The Destiny character id to retrieve. 471 membership_type: `aiobungie.internal.enums.MembershipType` 472 The member's membership type. 473 components: `list[aiobungie.ComponentType]` 474 Multiple arguments of character components to collect and return. 475 476 Other Parameters 477 ---------------- 478 auth : `typing.Optional[str]` 479 A Bearer access_token to make the request with. 480 This is optional and limited to components that only requires an Authorization token. 481 482 Returns 483 ------- 484 `aiobungie.crates.CharacterComponent` 485 A Bungie character component. 486 487 `aiobungie.MembershipTypeError` 488 The provided membership type was invalid. 489 """ 490 resp = await self.rest.fetch_character( 491 member_id, membership_type, character_id, components, auth 492 ) 493 494 return self.factory.deserialize_character_component(resp) 495 496 async def fetch_unique_weapon_history( 497 self, 498 membership_id: int, 499 character_id: int, 500 membership_type: typedefs.IntAnd[enums.MembershipType], 501 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 502 """Fetch details about unique weapon usage for a character. Includes all exotics. 503 504 Parameters 505 ---------- 506 membership_id : `int` 507 The Destiny user membership id. 508 character_id : `int` 509 The character id to retrieve. 510 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 511 The Destiny user's membership type. 512 513 Returns 514 ------- 515 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 516 A sequence of the weapon's extended values. 517 """ 518 resp = await self._rest.fetch_unique_weapon_history( 519 membership_id, character_id, membership_type 520 ) 521 522 return [ 523 self._factory.deserialize_extended_weapon_values(weapon) 524 for weapon in resp["weapons"] 525 ] 526 527 # * Destiny 2 Activities. 528 529 async def fetch_activities( 530 self, 531 member_id: int, 532 character_id: int, 533 mode: typedefs.IntAnd[enums.GameMode], 534 *, 535 membership_type: typedefs.IntAnd[ 536 enums.MembershipType 537 ] = enums.MembershipType.ALL, 538 page: int = 0, 539 limit: int = 250, 540 ) -> iterators.FlatIterator[activity.Activity]: 541 """Fetch a Destiny 2 activity for the specified character id. 542 543 Parameters 544 ---------- 545 member_id: `int` 546 The user id that starts with `4611`. 547 character_id: `int` 548 The id of the character to retrieve the activities for. 549 mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]` 550 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 551 552 Other Parameters 553 ---------------- 554 membership_type: `aiobungie.internal.enums.MembershipType` 555 The Member ship type, if nothing was passed than it will return all. 556 page: int 557 The page number. Default is `0` 558 limit: int 559 Limit the returned result. Default is `250`. 560 561 Returns 562 ------- 563 `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]` 564 An iterator of the player's activities. 565 566 Raises 567 ------ 568 `aiobungie.MembershipTypeError` 569 The provided membership type was invalid. 570 """ 571 resp = await self.rest.fetch_activities( 572 member_id, 573 character_id, 574 mode, 575 membership_type=membership_type, 576 page=page, 577 limit=limit, 578 ) 579 580 return self.factory.deserialize_activities(resp) 581 582 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 583 """Fetch a post activity details. 584 585 Parameters 586 ---------- 587 instance_id: `int` 588 The activity instance id. 589 590 Returns 591 ------- 592 `aiobungie.crates.PostActivity` 593 A post activity object. 594 """ 595 resp = await self.rest.fetch_post_activity(instance_id) 596 597 return self.factory.deserialize_post_activity(resp) 598 599 async def fetch_aggregated_activity_stats( 600 self, 601 character_id: int, 602 membership_id: int, 603 membership_type: typedefs.IntAnd[enums.MembershipType], 604 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 605 """Fetch aggregated activity stats for a character. 606 607 Parameters 608 ---------- 609 character_id: `int` 610 The id of the character to retrieve the activities for. 611 membership_id: `int` 612 The id of the user that started with `4611`. 613 membership_type: `aiobungie.internal.enums.MembershipType` 614 The Member ship type. 615 616 Returns 617 ------- 618 `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]` 619 An iterator of the player's activities. 620 621 Raises 622 ------ 623 `aiobungie.MembershipTypeError` 624 The provided membership type was invalid. 625 """ 626 resp = await self.rest.fetch_aggregated_activity_stats( 627 character_id, membership_id, membership_type 628 ) 629 630 return self.factory.deserialize_aggregated_activities(resp) 631 632 # * Destiny 2 Clans or GroupsV2. 633 634 async def fetch_clan_from_id( 635 self, 636 id: int, 637 /, 638 access_token: typing.Optional[str] = None, 639 ) -> clans.Clan: 640 """Fetch a Bungie Clan by its id. 641 642 Parameters 643 ----------- 644 id: `int` 645 The clan id. 646 647 Returns 648 -------- 649 `aiobungie.crates.Clan` 650 An Bungie clan. 651 652 Raises 653 ------ 654 `aiobungie.NotFound` 655 The clan was not found. 656 """ 657 resp = await self.rest.fetch_clan_from_id(id, access_token) 658 659 return self.factory.deserialize_clan(resp) 660 661 async def fetch_clan( 662 self, 663 name: str, 664 /, 665 access_token: typing.Optional[str] = None, 666 *, 667 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 668 ) -> clans.Clan: 669 """Fetch a Clan by its name. 670 This method will return the first clan found with given name. 671 672 Parameters 673 ---------- 674 name: `str` 675 The clan name 676 677 Other Parameters 678 ---------------- 679 access_token : `typing.Optional[str]` 680 An optional access token to make the request with. 681 682 If the token was bound to a member of the clan, 683 This field `aiobungie.crates.Clan.current_user_membership` will be available 684 and will return the membership of the user who made this request. 685 type : `aiobungie.GroupType` 686 The group type, Default is aiobungie.GroupType.CLAN. 687 688 Returns 689 ------- 690 `aiobungie.crates.Clan` 691 A Bungie clan. 692 693 Raises 694 ------ 695 `aiobungie.NotFound` 696 The clan was not found. 697 """ 698 resp = await self.rest.fetch_clan(name, access_token, type=type) 699 700 return self.factory.deserialize_clan(resp) 701 702 async def fetch_clan_conversations( 703 self, clan_id: int, / 704 ) -> collections.Sequence[clans.ClanConversation]: 705 """Fetch the conversations/chat channels of the given clan id. 706 707 Parameters 708 ---------- 709 clan_id : `int` 710 The clan id. 711 712 Returns 713 `collections.Sequence[aiobungie.crates.ClanConversation]` 714 A sequence of the clan chat channels. 715 """ 716 resp = await self.rest.fetch_clan_conversations(clan_id) 717 718 return self.factory.deserialize_clan_conversations(resp) 719 720 async def fetch_clan_admins( 721 self, clan_id: int, / 722 ) -> iterators.FlatIterator[clans.ClanMember]: 723 """Fetch the clan founder and admins. 724 725 Parameters 726 ---------- 727 clan_id : `int` 728 The clan id. 729 730 Returns 731 ------- 732 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 733 An iterator over the found clan admins and founder. 734 735 Raises 736 ------ 737 `aiobungie.NotFound` 738 The requested clan was not found. 739 """ 740 resp = await self.rest.fetch_clan_admins(clan_id) 741 742 return self.factory.deserialize_clan_members(resp) 743 744 async def fetch_groups_for_member( 745 self, 746 member_id: int, 747 member_type: typedefs.IntAnd[enums.MembershipType], 748 /, 749 *, 750 filter: int = 0, 751 group_type: enums.GroupType = enums.GroupType.CLAN, 752 ) -> collections.Sequence[clans.GroupMember]: 753 """Fetch information about the groups that a given member has joined. 754 755 Parameters 756 ---------- 757 member_id : `int` 758 The member's id 759 member_type : `aiobungie.MembershipType` 760 The member's membership type. 761 762 Other Parameters 763 ---------------- 764 filter : `int` 765 Filter apply to list of joined groups. This Default to `0` 766 group_type : `aiobungie.GroupType` 767 The group's type. 768 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 769 770 Returns 771 ------- 772 `collections.Sequence[aiobungie.crates.GroupMember]` 773 A sequence of joined groups for the fetched member. 774 """ 775 resp = await self.rest.fetch_groups_for_member( 776 member_id, member_type, filter=filter, group_type=group_type 777 ) 778 779 return [ 780 self.factory.deserialize_group_member(group) for group in resp["results"] 781 ] 782 783 async def fetch_potential_groups_for_member( 784 self, 785 member_id: int, 786 member_type: typedefs.IntAnd[enums.MembershipType], 787 /, 788 *, 789 filter: int = 0, 790 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 791 ) -> collections.Sequence[clans.GroupMember]: 792 """Fetch the potential groups for a clan member. 793 794 Parameters 795 ---------- 796 member_id : `int` 797 The member's id 798 member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 799 The member's membership type. 800 801 Other Parameters 802 ---------------- 803 filter : `int` 804 Filter apply to list of joined groups. This Default to `0` 805 group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]` 806 The group's type. 807 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 808 809 Returns 810 ------- 811 `collections.Sequence[aiobungie.crates.GroupMember]` 812 A sequence of joined potential groups for the fetched member. 813 """ 814 resp = await self.rest.fetch_potential_groups_for_member( 815 member_id, member_type, filter=filter, group_type=group_type 816 ) 817 818 return [ 819 self.factory.deserialize_group_member(group) for group in resp["results"] 820 ] 821 822 async def fetch_clan_members( 823 self, 824 clan_id: int, 825 /, 826 *, 827 name: typing.Optional[str] = None, 828 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 829 ) -> iterators.FlatIterator[clans.ClanMember]: 830 """Fetch Bungie clan members. 831 832 Parameters 833 ---------- 834 clan_id : `int` 835 The clans id 836 837 Other Parameters 838 ---------------- 839 name : `typing.Optional[str]` 840 If provided, Only players matching this name will be returned. 841 type : `aiobungie.MembershipType` 842 An optional clan member's membership type. 843 This parameter is used to filter the returned results 844 by the provided membership, For an example XBox memberships only, 845 Otherwise will return all memberships. 846 847 Returns 848 ------- 849 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 850 An iterator over the bungie clan members. 851 852 Raises 853 ------ 854 `aiobungie.NotFound` 855 The clan was not found. 856 """ 857 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 858 859 return self.factory.deserialize_clan_members(resp) 860 861 async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]: 862 """Fetch the clan banners. 863 864 Returns 865 ------- 866 `collections.Sequence[aiobungie.crates.ClanBanner]` 867 A sequence of the clan banners. 868 """ 869 resp = await self.rest.fetch_clan_banners() 870 871 return self.factory.deserialize_clan_banners(resp) 872 873 # This method is required to be here since it deserialize the clan. 874 async def kick_clan_member( 875 self, 876 access_token: str, 877 /, 878 group_id: int, 879 membership_id: int, 880 membership_type: typedefs.IntAnd[enums.MembershipType], 881 ) -> clans.Clan: 882 """Kick a member from the clan. 883 884 .. note:: 885 This request requires OAuth2: oauth2: `AdminGroups` scope. 886 887 Parameters 888 ---------- 889 access_token : `str` 890 The bearer access token associated with the bungie account. 891 group_id: `int` 892 The group id. 893 membership_id : `int` 894 The member id to kick. 895 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 896 The member's membership type. 897 898 Returns 899 ------- 900 `aiobungie.crates.clan.Clan` 901 The clan that the member was kicked from. 902 """ 903 resp = await self.rest.kick_clan_member( 904 access_token, 905 group_id=group_id, 906 membership_id=membership_id, 907 membership_type=membership_type, 908 ) 909 910 return self.factory.deserialize_clan(resp) 911 912 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 913 """Fetch a Bungie clan's weekly reward state. 914 915 Parameters 916 ---------- 917 clan_id : `int` 918 The clan's id. 919 920 Returns 921 ------- 922 `aiobungie.crates.Milestone` 923 A runtime status of the clan's milestone data. 924 """ 925 926 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 927 928 return self.factory.deserialize_milestone(resp) 929 930 # * Destiny 2 Entities aka Definitions. 931 932 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 933 """Fetch a static inventory item entity given a its hash. 934 935 Parameters 936 ---------- 937 hash: `int` 938 Inventory item's hash. 939 940 Returns 941 ------- 942 `aiobungie.crates.InventoryEntity` 943 A bungie inventory item. 944 """ 945 resp = await self.rest.fetch_inventory_item(hash) 946 947 return self.factory.deserialize_inventory_entity(resp) 948 949 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 950 """Fetch a Destiny objective entity given a its hash. 951 952 Parameters 953 ---------- 954 hash: `int` 955 objective's hash. 956 957 Returns 958 ------- 959 `aiobungie.crates.ObjectiveEntity` 960 An objective entity item. 961 """ 962 resp = await self.rest.fetch_objective_entity(hash) 963 964 return self.factory.deserialize_objective_entity(resp) 965 966 async def search_entities( 967 self, name: str, entity_type: str, *, page: int = 0 968 ) -> iterators.FlatIterator[entity.SearchableEntity]: 969 """Search for Destiny2 entities given a name and its type. 970 971 Parameters 972 ---------- 973 name : `str` 974 The name of the entity, i.e., Thunderlord, One thousand voices. 975 entity_type : `str` 976 The type of the entity, AKA Definition, 977 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 978 979 Other Parameters 980 ---------------- 981 page : `int` 982 An optional page to return. Default to 0. 983 984 Returns 985 ------- 986 `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]` 987 An iterator over the found results matching the provided name. 988 """ 989 resp = await self.rest.search_entities(name, entity_type, page=page) 990 991 return self.factory.deserialize_inventory_results(resp) 992 993 # Fireteams 994 995 async def fetch_fireteams( 996 self, 997 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 998 *, 999 platform: typedefs.IntAnd[ 1000 fireteams.FireteamPlatform 1001 ] = fireteams.FireteamPlatform.ANY, 1002 language: typing.Union[ 1003 fireteams.FireteamLanguage, str 1004 ] = fireteams.FireteamLanguage.ALL, 1005 date_range: int = 0, 1006 page: int = 0, 1007 slots_filter: int = 0, 1008 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1009 """Fetch public Bungie fireteams with open slots. 1010 1011 Parameters 1012 ---------- 1013 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1014 The fireteam activity type. 1015 1016 Other Parameters 1017 ---------------- 1018 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1019 If this is provided. Then the results will be filtered with the given platform. 1020 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1021 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1022 A locale language to filter the used language in that fireteam. 1023 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1024 date_range : `int` 1025 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1026 page : `int` 1027 The page number. By default its `0` which returns all available activities. 1028 slots_filter : `int` 1029 Filter the returned fireteams based on available slots. Default is `0` 1030 1031 Returns 1032 ------- 1033 `typing.Optional[collections.Sequence[fireteams.Fireteam]]` 1034 A sequence of `aiobungie.crates.Fireteam` or `None`. 1035 """ 1036 1037 resp = await self.rest.fetch_fireteams( 1038 activity_type, 1039 platform=platform, 1040 language=language, 1041 date_range=date_range, 1042 page=page, 1043 slots_filter=slots_filter, 1044 ) 1045 1046 return self.factory.deserialize_fireteams(resp) 1047 1048 async def fetch_avaliable_clan_fireteams( 1049 self, 1050 access_token: str, 1051 group_id: int, 1052 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1053 *, 1054 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1055 language: typing.Union[fireteams.FireteamLanguage, str], 1056 date_range: int = 0, 1057 page: int = 0, 1058 public_only: bool = False, 1059 slots_filter: int = 0, 1060 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1061 """Fetch a clan's fireteams with open slots. 1062 1063 .. note:: 1064 This method requires OAuth2: ReadGroups scope. 1065 1066 Parameters 1067 ---------- 1068 access_token : `str` 1069 The bearer access token associated with the bungie account. 1070 group_id : `int` 1071 The group/clan id of the fireteam. 1072 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1073 The fireteam activity type. 1074 1075 Other Parameters 1076 ---------------- 1077 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1078 If this is provided. Then the results will be filtered with the given platform. 1079 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1080 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1081 A locale language to filter the used language in that fireteam. 1082 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1083 date_range : `int` 1084 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1085 page : `int` 1086 The page number. By default its `0` which returns all available activities. 1087 public_only: `bool` 1088 If set to True, Then only public fireteams will be returned. 1089 slots_filter : `int` 1090 Filter the returned fireteams based on available slots. Default is `0` 1091 1092 Returns 1093 ------- 1094 `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]` 1095 A sequence of fireteams found in the clan. 1096 `None` will be returned if nothing was found. 1097 """ 1098 resp = await self.rest.fetch_avaliable_clan_fireteams( 1099 access_token, 1100 group_id, 1101 activity_type, 1102 platform=platform, 1103 language=language, 1104 date_range=date_range, 1105 page=page, 1106 public_only=public_only, 1107 slots_filter=slots_filter, 1108 ) 1109 1110 return self.factory.deserialize_fireteams(resp) 1111 1112 async def fetch_clan_fireteam( 1113 self, access_token: str, fireteam_id: int, group_id: int 1114 ) -> fireteams.AvailableFireteam: 1115 """Fetch a specific clan fireteam. 1116 1117 .. note:: 1118 This method requires OAuth2: ReadGroups scope. 1119 1120 Parameters 1121 ---------- 1122 access_token : `str` 1123 The bearer access token associated with the bungie account. 1124 group_id : `int` 1125 The group/clan id to fetch the fireteam from. 1126 fireteam_id : `int` 1127 The fireteam id to fetch. 1128 1129 Returns 1130 ------- 1131 `typing.Optional[aiobungie.crates.AvailableFireteam]` 1132 A sequence of available fireteams objects if exists. else `None` will be returned. 1133 """ 1134 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1135 1136 return self.factory.deserialize_available_fireteams( 1137 resp, no_results=True 1138 ) # type: ignore[return-value] 1139 1140 async def fetch_my_clan_fireteams( 1141 self, 1142 access_token: str, 1143 group_id: int, 1144 *, 1145 include_closed: bool = True, 1146 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1147 language: typing.Union[fireteams.FireteamLanguage, str], 1148 filtered: bool = True, 1149 page: int = 0, 1150 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1151 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1152 1153 .. note:: 1154 This method requires OAuth2: ReadGroups scope. 1155 1156 Parameters 1157 ---------- 1158 access_token : str 1159 The bearer access token associated with the bungie account. 1160 group_id : int 1161 The group/clan id to fetch. 1162 1163 Other Parameters 1164 ---------------- 1165 include_closed : bool 1166 If provided and set to True, It will also return closed fireteams. 1167 If provided and set to False, It will only return public fireteams. Default is True. 1168 platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform] 1169 If this is provided. Then the results will be filtered with the given platform. 1170 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1171 language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str] 1172 A locale language to filter the used language in that fireteam. 1173 Defaults to aiobungie.crates.FireteamLanguage.ALL 1174 filtered : bool 1175 If set to True, it will filter by clan. Otherwise not. Default is True. 1176 page : int 1177 The page number. By default its 0 which returns all available activities. 1178 1179 Returns 1180 ------- 1181 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1182 A sequence of available fireteams objects if exists. else `None` will be returned. 1183 """ 1184 resp = await self.rest.fetch_my_clan_fireteams( 1185 access_token, 1186 group_id, 1187 include_closed=include_closed, 1188 platform=platform, 1189 language=language, 1190 filtered=filtered, 1191 page=page, 1192 ) 1193 1194 return self.factory.deserialize_available_fireteams(resp) # type: ignore[return-value] 1195 1196 # Friends and social. 1197 1198 async def fetch_friends( 1199 self, access_token: str, / 1200 ) -> collections.Sequence[friends.Friend]: 1201 """Fetch bungie friend list. 1202 1203 .. note:: 1204 This requests OAuth2: ReadUserData scope. 1205 1206 Parameters 1207 ----------- 1208 access_token : `str` 1209 The bearer access token associated with the bungie account. 1210 1211 Returns 1212 ------- 1213 `collections.Sequence[aiobungie.crates.Friend]` 1214 A sequence of the friends associated with that access token. 1215 """ 1216 1217 resp = await self.rest.fetch_friends(access_token) 1218 1219 return self.factory.deserialize_friends(resp) 1220 1221 async def fetch_friend_requests( 1222 self, access_token: str, / 1223 ) -> friends.FriendRequestView: 1224 """Fetch pending bungie friend requests queue. 1225 1226 .. note:: 1227 This requests OAuth2: ReadUserData scope. 1228 1229 Parameters 1230 ----------- 1231 access_token : `str` 1232 The bearer access token associated with the bungie account. 1233 1234 Returns 1235 ------- 1236 `aiobungie.crates.FriendRequestView` 1237 A friend requests view of that associated access token. 1238 """ 1239 1240 resp = await self.rest.fetch_friend_requests(access_token) 1241 1242 return self.factory.deserialize_friend_requests(resp) 1243 1244 # Applications and Developer portal. 1245 1246 async def fetch_application(self, appid: int, /) -> application.Application: 1247 """Fetch a Bungie application. 1248 1249 Parameters 1250 ----------- 1251 appid: `int` 1252 The application id. 1253 1254 Returns 1255 -------- 1256 `aiobungie.crates.Application` 1257 A Bungie application. 1258 """ 1259 resp = await self.rest.fetch_application(appid) 1260 1261 return self.factory.deserialize_app(resp) 1262 1263 # Milestones 1264 1265 async def fetch_public_milestone_content( 1266 self, milestone_hash: int, / 1267 ) -> milestones.MilestoneContent: 1268 """Fetch the milestone content given its hash. 1269 1270 Parameters 1271 ---------- 1272 milestone_hash : `int` 1273 The milestone hash. 1274 1275 Returns 1276 ------- 1277 `aiobungie.crates.milestones.MilestoneContent` 1278 A milestone content object. 1279 """ 1280 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1281 1282 return self.factory.deserialize_public_milestone_content(resp)
Standard Bungie API client application.
This client deserialize the REST JSON responses using aiobungie.Factory
and returns aiobungie.crates Python object implementations of the responses.
A aiobungie.RESTClient REST client can also be used alone for low-level concepts.
Parameters
- token (
str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
- rest_client (
aiobungie.interfaces.RESTInterface | None): An optional rest client instance you can pass. If set toNonethen the client will use the default instance. - max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
94 def __init__( 95 self, 96 token: str, 97 /, 98 client_secret: typing.Optional[str] = None, 99 client_id: typing.Optional[int] = None, 100 *, 101 rest_client: typing.Optional[interfaces.RESTInterface] = None, 102 max_retries: int = 4, 103 max_ratelimit_retries: int = 3, 104 ) -> None: 105 106 self._client_secret = client_secret 107 self._client_id = client_id 108 109 self._rest = ( 110 rest_client 111 if rest_client is not None 112 else rest_.RESTClient( 113 token, 114 client_secret, 115 client_id, 116 max_retries=max_retries, 117 max_ratelimit_retries=max_ratelimit_retries, 118 ) 119 ) 120 121 self._factory = factory_.Factory(self)
A mutable mapping storage for the user's needs.
139 def run( 140 self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False 141 ) -> None: 142 loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop() 143 try: 144 if not loop.is_running(): 145 loop.set_debug(debug) 146 loop.run_until_complete(future) 147 148 except Exception as exc: 149 raise RuntimeError(f"Failed to run {future.__qualname__}") from exc 150 151 except KeyboardInterrupt: 152 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 153 return 154 155 finally: 156 if self._rest.is_alive: 157 # Clean up sessions. 158 loop.run_until_complete(self._rest.close())
Runs a coroutine function until its complete.
This is equivalent to asyncio.get_event_loop().run_until_complete(...)
Parameters
- future (
collections.Coroutine[None, None, None]): A coroutine object. - debug (
bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
await fetch(...)
# Run the coroutine.
client.run(main())
162 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 163 """Fetch and return a user object of the bungie net user associated with account. 164 165 .. warning:: 166 This method requires OAuth2 scope and a Bearer access token. 167 168 Parameters 169 ---------- 170 access_token : `str` 171 A valid Bearer access token for the authorization. 172 173 Returns 174 ------- 175 `aiobungie.crates.user.User` 176 A user object includes the Destiny memberships and Bungie.net user. 177 """ 178 resp = await self.rest.fetch_current_user_memberships(access_token) 179 180 return self.factory.deserialize_user(resp)
Fetch and return a user object of the bungie net user associated with account.
This method requires OAuth2 scope and a Bearer access token.
Parameters
- access_token (
str): A valid Bearer access token for the authorization.
Returns
aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
182 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 183 """Fetch a Bungie user by their BungieNet id. 184 185 .. note:: 186 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 187 for other memberships. 188 189 Parameters 190 ---------- 191 id: `int` 192 The user id. 193 194 Returns 195 ------- 196 `aiobungie.crates.user.BungieUser` 197 A Bungie user. 198 199 Raises 200 ------ 201 `aiobungie.error.NotFound` 202 The user was not found. 203 """ 204 payload = await self.rest.fetch_bungie_user(id) 205 206 return self.factory.deserialize_bungie_user(payload)
Fetch a Bungie user by their BungieNet id.
This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id
for other memberships.
Parameters
- id (
int): The user id.
Returns
aiobungie.crates.user.BungieUser: A Bungie user.
Raises
aiobungie.NotFound: The user was not found.
208 async def search_users( 209 self, name: str, / 210 ) -> iterators.FlatIterator[user.SearchableDestinyUser]: 211 """Search for players and return all players that matches the same name. 212 213 Parameters 214 ---------- 215 name : `buildins.str` 216 The user name. 217 218 Returns 219 ------- 220 `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]` 221 A sequence of destiny memberships. 222 """ 223 payload = await self.rest.search_users(name) 224 225 return iterators.FlatIterator( 226 [ 227 self.factory.deserialize_searched_user(user) 228 for user in payload["searchResults"] 229 ] 230 )
Search for players and return all players that matches the same name.
Parameters
- name (
buildins.str): The user name.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]: A sequence of destiny memberships.
232 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 233 """Fetch all available user themes. 234 235 Returns 236 ------- 237 `collections.Sequence[aiobungie.crates.user.UserThemes]` 238 A sequence of user themes. 239 """ 240 data = await self.rest.fetch_user_themes() 241 242 return self.factory.deserialize_user_themes(data)
Fetch all available user themes.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
244 async def fetch_hard_types( 245 self, 246 credential: int, 247 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 248 /, 249 ) -> user.HardLinkedMembership: 250 """Gets any hard linked membership given a credential. 251 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 252 Cross Save aware. 253 254 Parameters 255 ---------- 256 credential: `int` 257 A valid SteamID64 258 type: `aiobungie.CredentialType` 259 The credential type. This must not be changed 260 Since its only credential that works "currently" 261 262 Returns 263 ------- 264 `aiobungie.crates.user.HardLinkedMembership` 265 Information about the hard linked data. 266 """ 267 268 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 269 270 return user.HardLinkedMembership( 271 id=int(payload["membershipId"]), 272 type=enums.MembershipType(payload["membershipType"]), 273 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 274 )
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
276 async def fetch_membership_from_id( 277 self, 278 id: int, 279 /, 280 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 281 ) -> user.User: 282 """Fetch Bungie user's memberships from their id. 283 284 Notes 285 ----- 286 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 287 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 288 see `aiobungie.crates.user.DestinyMembership` for more details. 289 * If you only want the bungie user. Consider using `Client.fetch_user` method. 290 291 Parameters 292 ---------- 293 id : `int` 294 The user's id. 295 type : `aiobungie.MembershipType` 296 The user's membership type. 297 298 Returns 299 ------- 300 `aiobungie.crates.User` 301 A Bungie user with their membership types. 302 303 Raises 304 ------ 305 aiobungie.NotFound 306 The requested user was not found. 307 """ 308 payload = await self.rest.fetch_membership_from_id(id, type) 309 310 return self.factory.deserialize_user(payload)
Fetch Bungie user's memberships from their id.
Notes
- This returns both BungieNet membership and a sequence of the player's DestinyMemberships
Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
see
aiobungie.crates.user.DestinyMembershipfor more details. - If you only want the bungie user. Consider using
Client.fetch_usermethod.
Parameters
- id (
int): The user's id. - type (
aiobungie.MembershipType): The user's membership type.
Returns
aiobungie.crates.User: A Bungie user with their membership types.
Raises
- aiobungie.NotFound: The requested user was not found.
312 async def fetch_user_credentials( 313 self, access_token: str, membership_id: int, / 314 ) -> collections.Sequence[user.UserCredentials]: 315 """Fetch an array of credential types attached to the requested account. 316 317 .. note:: 318 This method require OAuth2 Bearer access token. 319 320 Parameters 321 ---------- 322 access_token : `str` 323 The bearer access token associated with the bungie account. 324 membership_id : `int` 325 The id of the membership to return. 326 327 Returns 328 ------- 329 `collections.Sequence[aiobungie.crates.UserCredentials]` 330 A sequence of the attached user credentials. 331 332 Raises 333 ------ 334 `aiobungie.Unauthorized` 335 The access token was wrong or no access token passed. 336 """ 337 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 338 339 return self.factory.deserialize_user_credentials(resp)
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of the attached user credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
343 async def fetch_profile( 344 self, 345 member_id: int, 346 type: typedefs.IntAnd[enums.MembershipType], 347 components: list[enums.ComponentType], 348 auth: typing.Optional[str] = None, 349 ) -> components.Component: 350 """ 351 Fetch a bungie profile passing components to the request. 352 353 Parameters 354 ---------- 355 member_id: `int` 356 The member's id. 357 type: `aiobungie.MembershipType` 358 A valid membership type. 359 components : `list[aiobungie.ComponentType]` 360 List of profile components to collect and return. 361 362 Other Parameters 363 ---------------- 364 auth : `typing.Optional[str]` 365 A Bearer access_token to make the request with. 366 This is optional and limited to components that only requires an Authorization token. 367 368 Returns 369 -------- 370 `aiobungie.crates.Component` 371 A Destiny 2 player profile with its components. 372 Only passed components will be available if they exists. Otherwise they will be `None` 373 374 Raises 375 ------ 376 `aiobungie.MembershipTypeError` 377 The provided membership type was invalid. 378 """ 379 data = await self.rest.fetch_profile(member_id, type, components, auth) 380 return self.factory.deserialize_components(data)
Fetch a bungie profile passing components to the request.
Parameters
- member_id (
int): The member's id. - type (
aiobungie.MembershipType): A valid membership type. - components (
list[aiobungie.ComponentType]): List of profile components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will beNone
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
382 async def fetch_linked_profiles( 383 self, 384 member_id: int, 385 member_type: typedefs.IntAnd[enums.MembershipType], 386 /, 387 *, 388 all: bool = False, 389 ) -> profile.LinkedProfile: 390 """Returns a summary information about all profiles linked to the requested member. 391 392 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 393 394 .. note:: 395 It will only return linked accounts whose linkages you are allowed to view. 396 397 Parameters 398 ---------- 399 member_id : `int` 400 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 401 member_type : `aiobungie.MembershipType` 402 The type for the membership whose linked Destiny account you want to return. 403 404 Other Parameters 405 ---------------- 406 all : `bool` 407 If provided and set to `True`, All memberships regardless 408 of whether they're obscured by overrides will be returned, 409 410 If provided and set to `False`, Only available memberships will be returned. 411 The default for this is `False`. 412 413 Returns 414 ------- 415 `aiobungie.crates.profile.LinkedProfile` 416 A linked profile object. 417 """ 418 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 419 420 return self.factory.deserialize_linked_profiles(resp)
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether they're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.crates.profile.LinkedProfile: A linked profile object.
422 async def fetch_player( 423 self, 424 name: str, 425 code: int, 426 /, 427 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 428 ) -> collections.Sequence[user.DestinyMembership]: 429 """Fetch a Destiny 2 player's memberships. 430 431 Parameters 432 ----------- 433 name: `str` 434 The unique Bungie player name. 435 code : `int` 436 The unique Bungie display name code. 437 type: `aiobungie.internal.enums.MembershipType` 438 The player's membership type, e,g. XBOX, STEAM, PSN 439 440 Returns 441 -------- 442 `collections.Sequence[aiobungie.crates.DestinyMembership]` 443 A sequence of the found Destiny 2 player memberships. 444 An empty sequence will be returned if no one found. 445 446 Raises 447 ------ 448 `aiobungie.MembershipTypeError` 449 The provided membership type was invalid. 450 """ 451 resp = await self.rest.fetch_player(name, code, type) 452 453 return self.factory.deserialize_destiny_memberships(resp)
Fetch a Destiny 2 player's memberships.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
aiobungie.MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
collections.Sequence[aiobungie.crates.DestinyMembership]: A sequence of the found Destiny 2 player memberships. An empty sequence will be returned if no one found.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
455 async def fetch_character( 456 self, 457 member_id: int, 458 membership_type: typedefs.IntAnd[enums.MembershipType], 459 character_id: int, 460 components: list[enums.ComponentType], 461 auth: typing.Optional[str] = None, 462 ) -> components.CharacterComponent: 463 """Fetch a Destiny 2 character. 464 465 Parameters 466 ---------- 467 member_id: `int` 468 A valid bungie member id. 469 character_id: `int` 470 The Destiny character id to retrieve. 471 membership_type: `aiobungie.internal.enums.MembershipType` 472 The member's membership type. 473 components: `list[aiobungie.ComponentType]` 474 Multiple arguments of character components to collect and return. 475 476 Other Parameters 477 ---------------- 478 auth : `typing.Optional[str]` 479 A Bearer access_token to make the request with. 480 This is optional and limited to components that only requires an Authorization token. 481 482 Returns 483 ------- 484 `aiobungie.crates.CharacterComponent` 485 A Bungie character component. 486 487 `aiobungie.MembershipTypeError` 488 The provided membership type was invalid. 489 """ 490 resp = await self.rest.fetch_character( 491 member_id, membership_type, character_id, components, auth 492 ) 493 494 return self.factory.deserialize_character_component(resp)
Fetch a Destiny 2 character.
Parameters
- member_id (
int): A valid bungie member id. - character_id (
int): The Destiny character id to retrieve. - membership_type (
aiobungie.MembershipType): The member's membership type. - components (
list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.CharacterComponent: A Bungie character component.aiobungie.MembershipTypeError: The provided membership type was invalid.
496 async def fetch_unique_weapon_history( 497 self, 498 membership_id: int, 499 character_id: int, 500 membership_type: typedefs.IntAnd[enums.MembershipType], 501 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 502 """Fetch details about unique weapon usage for a character. Includes all exotics. 503 504 Parameters 505 ---------- 506 membership_id : `int` 507 The Destiny user membership id. 508 character_id : `int` 509 The character id to retrieve. 510 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 511 The Destiny user's membership type. 512 513 Returns 514 ------- 515 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 516 A sequence of the weapon's extended values. 517 """ 518 resp = await self._rest.fetch_unique_weapon_history( 519 membership_id, character_id, membership_type 520 ) 521 522 return [ 523 self._factory.deserialize_extended_weapon_values(weapon) 524 for weapon in resp["weapons"] 525 ]
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny user's membership type.
Returns
collections.Sequence[aiobungie.crates.ExtendedWeaponValues]: A sequence of the weapon's extended values.
529 async def fetch_activities( 530 self, 531 member_id: int, 532 character_id: int, 533 mode: typedefs.IntAnd[enums.GameMode], 534 *, 535 membership_type: typedefs.IntAnd[ 536 enums.MembershipType 537 ] = enums.MembershipType.ALL, 538 page: int = 0, 539 limit: int = 250, 540 ) -> iterators.FlatIterator[activity.Activity]: 541 """Fetch a Destiny 2 activity for the specified character id. 542 543 Parameters 544 ---------- 545 member_id: `int` 546 The user id that starts with `4611`. 547 character_id: `int` 548 The id of the character to retrieve the activities for. 549 mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]` 550 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 551 552 Other Parameters 553 ---------------- 554 membership_type: `aiobungie.internal.enums.MembershipType` 555 The Member ship type, if nothing was passed than it will return all. 556 page: int 557 The page number. Default is `0` 558 limit: int 559 Limit the returned result. Default is `250`. 560 561 Returns 562 ------- 563 `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]` 564 An iterator of the player's activities. 565 566 Raises 567 ------ 568 `aiobungie.MembershipTypeError` 569 The provided membership type was invalid. 570 """ 571 resp = await self.rest.fetch_activities( 572 member_id, 573 character_id, 574 mode, 575 membership_type=membership_type, 576 page=page, 577 limit=limit, 578 ) 579 580 return self.factory.deserialize_activities(resp)
Fetch a Destiny 2 activity for the specified character id.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve the activities for. - mode (
aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
aiobungie.MembershipType): The Member ship type, if nothing was passed than it will return all. - page (int):
The page number. Default is
0 - limit (int):
Limit the returned result. Default is
250.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
582 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 583 """Fetch a post activity details. 584 585 Parameters 586 ---------- 587 instance_id: `int` 588 The activity instance id. 589 590 Returns 591 ------- 592 `aiobungie.crates.PostActivity` 593 A post activity object. 594 """ 595 resp = await self.rest.fetch_post_activity(instance_id) 596 597 return self.factory.deserialize_post_activity(resp)
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.crates.PostActivity: A post activity object.
599 async def fetch_aggregated_activity_stats( 600 self, 601 character_id: int, 602 membership_id: int, 603 membership_type: typedefs.IntAnd[enums.MembershipType], 604 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 605 """Fetch aggregated activity stats for a character. 606 607 Parameters 608 ---------- 609 character_id: `int` 610 The id of the character to retrieve the activities for. 611 membership_id: `int` 612 The id of the user that started with `4611`. 613 membership_type: `aiobungie.internal.enums.MembershipType` 614 The Member ship type. 615 616 Returns 617 ------- 618 `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]` 619 An iterator of the player's activities. 620 621 Raises 622 ------ 623 `aiobungie.MembershipTypeError` 624 The provided membership type was invalid. 625 """ 626 resp = await self.rest.fetch_aggregated_activity_stats( 627 character_id, membership_id, membership_type 628 ) 629 630 return self.factory.deserialize_aggregated_activities(resp)
Fetch aggregated activity stats for a character.
Parameters
- character_id (
int): The id of the character to retrieve the activities for. - membership_id (
int): The id of the user that started with4611. - membership_type (
aiobungie.MembershipType): The Member ship type.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
634 async def fetch_clan_from_id( 635 self, 636 id: int, 637 /, 638 access_token: typing.Optional[str] = None, 639 ) -> clans.Clan: 640 """Fetch a Bungie Clan by its id. 641 642 Parameters 643 ----------- 644 id: `int` 645 The clan id. 646 647 Returns 648 -------- 649 `aiobungie.crates.Clan` 650 An Bungie clan. 651 652 Raises 653 ------ 654 `aiobungie.NotFound` 655 The clan was not found. 656 """ 657 resp = await self.rest.fetch_clan_from_id(id, access_token) 658 659 return self.factory.deserialize_clan(resp)
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Returns
aiobungie.crates.Clan: An Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
661 async def fetch_clan( 662 self, 663 name: str, 664 /, 665 access_token: typing.Optional[str] = None, 666 *, 667 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 668 ) -> clans.Clan: 669 """Fetch a Clan by its name. 670 This method will return the first clan found with given name. 671 672 Parameters 673 ---------- 674 name: `str` 675 The clan name 676 677 Other Parameters 678 ---------------- 679 access_token : `typing.Optional[str]` 680 An optional access token to make the request with. 681 682 If the token was bound to a member of the clan, 683 This field `aiobungie.crates.Clan.current_user_membership` will be available 684 and will return the membership of the user who made this request. 685 type : `aiobungie.GroupType` 686 The group type, Default is aiobungie.GroupType.CLAN. 687 688 Returns 689 ------- 690 `aiobungie.crates.Clan` 691 A Bungie clan. 692 693 Raises 694 ------ 695 `aiobungie.NotFound` 696 The clan was not found. 697 """ 698 resp = await self.rest.fetch_clan(name, access_token, type=type) 699 700 return self.factory.deserialize_clan(resp)
Fetch a Clan by its name. This method will return the first clan found with given name.
Parameters
- name (
str): The clan name
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.GroupType): The group type, Default is aiobungie.GroupType.CLAN.
Returns
aiobungie.crates.Clan: A Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
702 async def fetch_clan_conversations( 703 self, clan_id: int, / 704 ) -> collections.Sequence[clans.ClanConversation]: 705 """Fetch the conversations/chat channels of the given clan id. 706 707 Parameters 708 ---------- 709 clan_id : `int` 710 The clan id. 711 712 Returns 713 `collections.Sequence[aiobungie.crates.ClanConversation]` 714 A sequence of the clan chat channels. 715 """ 716 resp = await self.rest.fetch_clan_conversations(clan_id) 717 718 return self.factory.deserialize_clan_conversations(resp)
Fetch the conversations/chat channels of the given clan id.
Parameters
- clan_id (
int): The clan id. - Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of the clan chat channels.
720 async def fetch_clan_admins( 721 self, clan_id: int, / 722 ) -> iterators.FlatIterator[clans.ClanMember]: 723 """Fetch the clan founder and admins. 724 725 Parameters 726 ---------- 727 clan_id : `int` 728 The clan id. 729 730 Returns 731 ------- 732 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 733 An iterator over the found clan admins and founder. 734 735 Raises 736 ------ 737 `aiobungie.NotFound` 738 The requested clan was not found. 739 """ 740 resp = await self.rest.fetch_clan_admins(clan_id) 741 742 return self.factory.deserialize_clan_members(resp)
Fetch the clan founder and admins.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]: An iterator over the found clan admins and founder.
Raises
aiobungie.NotFound: The requested clan was not found.
744 async def fetch_groups_for_member( 745 self, 746 member_id: int, 747 member_type: typedefs.IntAnd[enums.MembershipType], 748 /, 749 *, 750 filter: int = 0, 751 group_type: enums.GroupType = enums.GroupType.CLAN, 752 ) -> collections.Sequence[clans.GroupMember]: 753 """Fetch information about the groups that a given member has joined. 754 755 Parameters 756 ---------- 757 member_id : `int` 758 The member's id 759 member_type : `aiobungie.MembershipType` 760 The member's membership type. 761 762 Other Parameters 763 ---------------- 764 filter : `int` 765 Filter apply to list of joined groups. This Default to `0` 766 group_type : `aiobungie.GroupType` 767 The group's type. 768 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 769 770 Returns 771 ------- 772 `collections.Sequence[aiobungie.crates.GroupMember]` 773 A sequence of joined groups for the fetched member. 774 """ 775 resp = await self.rest.fetch_groups_for_member( 776 member_id, member_type, filter=filter, group_type=group_type 777 ) 778 779 return [ 780 self.factory.deserialize_group_member(group) for group in resp["results"] 781 ]
Fetch information about the groups that a given member has joined.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.MembershipType): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.GroupType): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined groups for the fetched member.
783 async def fetch_potential_groups_for_member( 784 self, 785 member_id: int, 786 member_type: typedefs.IntAnd[enums.MembershipType], 787 /, 788 *, 789 filter: int = 0, 790 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 791 ) -> collections.Sequence[clans.GroupMember]: 792 """Fetch the potential groups for a clan member. 793 794 Parameters 795 ---------- 796 member_id : `int` 797 The member's id 798 member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 799 The member's membership type. 800 801 Other Parameters 802 ---------------- 803 filter : `int` 804 Filter apply to list of joined groups. This Default to `0` 805 group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]` 806 The group's type. 807 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 808 809 Returns 810 ------- 811 `collections.Sequence[aiobungie.crates.GroupMember]` 812 A sequence of joined potential groups for the fetched member. 813 """ 814 resp = await self.rest.fetch_potential_groups_for_member( 815 member_id, member_type, filter=filter, group_type=group_type 816 ) 817 818 return [ 819 self.factory.deserialize_group_member(group) for group in resp["results"] 820 ]
Fetch the potential groups for a clan member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined potential groups for the fetched member.
822 async def fetch_clan_members( 823 self, 824 clan_id: int, 825 /, 826 *, 827 name: typing.Optional[str] = None, 828 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 829 ) -> iterators.FlatIterator[clans.ClanMember]: 830 """Fetch Bungie clan members. 831 832 Parameters 833 ---------- 834 clan_id : `int` 835 The clans id 836 837 Other Parameters 838 ---------------- 839 name : `typing.Optional[str]` 840 If provided, Only players matching this name will be returned. 841 type : `aiobungie.MembershipType` 842 An optional clan member's membership type. 843 This parameter is used to filter the returned results 844 by the provided membership, For an example XBox memberships only, 845 Otherwise will return all memberships. 846 847 Returns 848 ------- 849 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 850 An iterator over the bungie clan members. 851 852 Raises 853 ------ 854 `aiobungie.NotFound` 855 The clan was not found. 856 """ 857 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 858 859 return self.factory.deserialize_clan_members(resp)
Fetch Bungie clan members.
Parameters
- clan_id (
int): The clans id
Other Parameters
- name (
typing.Optional[str]): If provided, Only players matching this name will be returned. - type (
aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]: An iterator over the bungie clan members.
Raises
aiobungie.NotFound: The clan was not found.
874 async def kick_clan_member( 875 self, 876 access_token: str, 877 /, 878 group_id: int, 879 membership_id: int, 880 membership_type: typedefs.IntAnd[enums.MembershipType], 881 ) -> clans.Clan: 882 """Kick a member from the clan. 883 884 .. note:: 885 This request requires OAuth2: oauth2: `AdminGroups` scope. 886 887 Parameters 888 ---------- 889 access_token : `str` 890 The bearer access token associated with the bungie account. 891 group_id: `int` 892 The group id. 893 membership_id : `int` 894 The member id to kick. 895 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 896 The member's membership type. 897 898 Returns 899 ------- 900 `aiobungie.crates.clan.Clan` 901 The clan that the member was kicked from. 902 """ 903 resp = await self.rest.kick_clan_member( 904 access_token, 905 group_id=group_id, 906 membership_id=membership_id, 907 membership_type=membership_type, 908 ) 909 910 return self.factory.deserialize_clan(resp)
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
aiobungie.crates.clan.Clan: The clan that the member was kicked from.
912 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 913 """Fetch a Bungie clan's weekly reward state. 914 915 Parameters 916 ---------- 917 clan_id : `int` 918 The clan's id. 919 920 Returns 921 ------- 922 `aiobungie.crates.Milestone` 923 A runtime status of the clan's milestone data. 924 """ 925 926 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 927 928 return self.factory.deserialize_milestone(resp)
Fetch a Bungie clan's weekly reward state.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.crates.Milestone: A runtime status of the clan's milestone data.
932 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 933 """Fetch a static inventory item entity given a its hash. 934 935 Parameters 936 ---------- 937 hash: `int` 938 Inventory item's hash. 939 940 Returns 941 ------- 942 `aiobungie.crates.InventoryEntity` 943 A bungie inventory item. 944 """ 945 resp = await self.rest.fetch_inventory_item(hash) 946 947 return self.factory.deserialize_inventory_entity(resp)
Fetch a static inventory item entity given a its hash.
Parameters
- hash (
int): Inventory item's hash.
Returns
aiobungie.crates.InventoryEntity: A bungie inventory item.
949 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 950 """Fetch a Destiny objective entity given a its hash. 951 952 Parameters 953 ---------- 954 hash: `int` 955 objective's hash. 956 957 Returns 958 ------- 959 `aiobungie.crates.ObjectiveEntity` 960 An objective entity item. 961 """ 962 resp = await self.rest.fetch_objective_entity(hash) 963 964 return self.factory.deserialize_objective_entity(resp)
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity item.
966 async def search_entities( 967 self, name: str, entity_type: str, *, page: int = 0 968 ) -> iterators.FlatIterator[entity.SearchableEntity]: 969 """Search for Destiny2 entities given a name and its type. 970 971 Parameters 972 ---------- 973 name : `str` 974 The name of the entity, i.e., Thunderlord, One thousand voices. 975 entity_type : `str` 976 The type of the entity, AKA Definition, 977 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 978 979 Other Parameters 980 ---------------- 981 page : `int` 982 An optional page to return. Default to 0. 983 984 Returns 985 ------- 986 `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]` 987 An iterator over the found results matching the provided name. 988 """ 989 resp = await self.rest.search_entities(name, entity_type, page=page) 990 991 return self.factory.deserialize_inventory_results(resp)
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinitionfor emblems, weapons, and other inventory items.
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]: An iterator over the found results matching the provided name.
995 async def fetch_fireteams( 996 self, 997 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 998 *, 999 platform: typedefs.IntAnd[ 1000 fireteams.FireteamPlatform 1001 ] = fireteams.FireteamPlatform.ANY, 1002 language: typing.Union[ 1003 fireteams.FireteamLanguage, str 1004 ] = fireteams.FireteamLanguage.ALL, 1005 date_range: int = 0, 1006 page: int = 0, 1007 slots_filter: int = 0, 1008 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1009 """Fetch public Bungie fireteams with open slots. 1010 1011 Parameters 1012 ---------- 1013 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1014 The fireteam activity type. 1015 1016 Other Parameters 1017 ---------------- 1018 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1019 If this is provided. Then the results will be filtered with the given platform. 1020 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1021 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1022 A locale language to filter the used language in that fireteam. 1023 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1024 date_range : `int` 1025 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1026 page : `int` 1027 The page number. By default its `0` which returns all available activities. 1028 slots_filter : `int` 1029 Filter the returned fireteams based on available slots. Default is `0` 1030 1031 Returns 1032 ------- 1033 `typing.Optional[collections.Sequence[fireteams.Fireteam]]` 1034 A sequence of `aiobungie.crates.Fireteam` or `None`. 1035 """ 1036 1037 resp = await self.rest.fetch_fireteams( 1038 activity_type, 1039 platform=platform, 1040 language=language, 1041 date_range=date_range, 1042 page=page, 1043 slots_filter=slots_filter, 1044 ) 1045 1046 return self.factory.deserialize_fireteams(resp)
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
typing.Optional[collections.Sequence[fireteams.Fireteam]]: A sequence ofaiobungie.crates.FireteamorNone.
1048 async def fetch_avaliable_clan_fireteams( 1049 self, 1050 access_token: str, 1051 group_id: int, 1052 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1053 *, 1054 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1055 language: typing.Union[fireteams.FireteamLanguage, str], 1056 date_range: int = 0, 1057 page: int = 0, 1058 public_only: bool = False, 1059 slots_filter: int = 0, 1060 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1061 """Fetch a clan's fireteams with open slots. 1062 1063 .. note:: 1064 This method requires OAuth2: ReadGroups scope. 1065 1066 Parameters 1067 ---------- 1068 access_token : `str` 1069 The bearer access token associated with the bungie account. 1070 group_id : `int` 1071 The group/clan id of the fireteam. 1072 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1073 The fireteam activity type. 1074 1075 Other Parameters 1076 ---------------- 1077 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1078 If this is provided. Then the results will be filtered with the given platform. 1079 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1080 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1081 A locale language to filter the used language in that fireteam. 1082 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1083 date_range : `int` 1084 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1085 page : `int` 1086 The page number. By default its `0` which returns all available activities. 1087 public_only: `bool` 1088 If set to True, Then only public fireteams will be returned. 1089 slots_filter : `int` 1090 Filter the returned fireteams based on available slots. Default is `0` 1091 1092 Returns 1093 ------- 1094 `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]` 1095 A sequence of fireteams found in the clan. 1096 `None` will be returned if nothing was found. 1097 """ 1098 resp = await self.rest.fetch_avaliable_clan_fireteams( 1099 access_token, 1100 group_id, 1101 activity_type, 1102 platform=platform, 1103 language=language, 1104 date_range=date_range, 1105 page=page, 1106 public_only=public_only, 1107 slots_filter=slots_filter, 1108 ) 1109 1110 return self.factory.deserialize_fireteams(resp)
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults to0. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]: A sequence of fireteams found in the clan.Nonewill be returned if nothing was found.
1112 async def fetch_clan_fireteam( 1113 self, access_token: str, fireteam_id: int, group_id: int 1114 ) -> fireteams.AvailableFireteam: 1115 """Fetch a specific clan fireteam. 1116 1117 .. note:: 1118 This method requires OAuth2: ReadGroups scope. 1119 1120 Parameters 1121 ---------- 1122 access_token : `str` 1123 The bearer access token associated with the bungie account. 1124 group_id : `int` 1125 The group/clan id to fetch the fireteam from. 1126 fireteam_id : `int` 1127 The fireteam id to fetch. 1128 1129 Returns 1130 ------- 1131 `typing.Optional[aiobungie.crates.AvailableFireteam]` 1132 A sequence of available fireteams objects if exists. else `None` will be returned. 1133 """ 1134 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1135 1136 return self.factory.deserialize_available_fireteams( 1137 resp, no_results=True 1138 ) # type: ignore[return-value]
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
typing.Optional[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1140 async def fetch_my_clan_fireteams( 1141 self, 1142 access_token: str, 1143 group_id: int, 1144 *, 1145 include_closed: bool = True, 1146 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1147 language: typing.Union[fireteams.FireteamLanguage, str], 1148 filtered: bool = True, 1149 page: int = 0, 1150 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1151 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1152 1153 .. note:: 1154 This method requires OAuth2: ReadGroups scope. 1155 1156 Parameters 1157 ---------- 1158 access_token : str 1159 The bearer access token associated with the bungie account. 1160 group_id : int 1161 The group/clan id to fetch. 1162 1163 Other Parameters 1164 ---------------- 1165 include_closed : bool 1166 If provided and set to True, It will also return closed fireteams. 1167 If provided and set to False, It will only return public fireteams. Default is True. 1168 platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform] 1169 If this is provided. Then the results will be filtered with the given platform. 1170 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1171 language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str] 1172 A locale language to filter the used language in that fireteam. 1173 Defaults to aiobungie.crates.FireteamLanguage.ALL 1174 filtered : bool 1175 If set to True, it will filter by clan. Otherwise not. Default is True. 1176 page : int 1177 The page number. By default its 0 which returns all available activities. 1178 1179 Returns 1180 ------- 1181 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1182 A sequence of available fireteams objects if exists. else `None` will be returned. 1183 """ 1184 resp = await self.rest.fetch_my_clan_fireteams( 1185 access_token, 1186 group_id, 1187 include_closed=include_closed, 1188 platform=platform, 1189 language=language, 1190 filtered=filtered, 1191 page=page, 1192 ) 1193 1194 return self.factory.deserialize_available_fireteams(resp) # type: ignore[return-value]
A method that's similar to fetch_fireteams but requires OAuth2.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (str): The bearer access token associated with the bungie account.
- group_id (int): The group/clan id to fetch.
Other Parameters
- include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
- platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
- language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
- filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
- page (int): The page number. By default its 0 which returns all available activities.
Returns
collections.Sequence[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1198 async def fetch_friends( 1199 self, access_token: str, / 1200 ) -> collections.Sequence[friends.Friend]: 1201 """Fetch bungie friend list. 1202 1203 .. note:: 1204 This requests OAuth2: ReadUserData scope. 1205 1206 Parameters 1207 ----------- 1208 access_token : `str` 1209 The bearer access token associated with the bungie account. 1210 1211 Returns 1212 ------- 1213 `collections.Sequence[aiobungie.crates.Friend]` 1214 A sequence of the friends associated with that access token. 1215 """ 1216 1217 resp = await self.rest.fetch_friends(access_token) 1218 1219 return self.factory.deserialize_friends(resp)
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of the friends associated with that access token.
1221 async def fetch_friend_requests( 1222 self, access_token: str, / 1223 ) -> friends.FriendRequestView: 1224 """Fetch pending bungie friend requests queue. 1225 1226 .. note:: 1227 This requests OAuth2: ReadUserData scope. 1228 1229 Parameters 1230 ----------- 1231 access_token : `str` 1232 The bearer access token associated with the bungie account. 1233 1234 Returns 1235 ------- 1236 `aiobungie.crates.FriendRequestView` 1237 A friend requests view of that associated access token. 1238 """ 1239 1240 resp = await self.rest.fetch_friend_requests(access_token) 1241 1242 return self.factory.deserialize_friend_requests(resp)
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.crates.FriendRequestView: A friend requests view of that associated access token.
1246 async def fetch_application(self, appid: int, /) -> application.Application: 1247 """Fetch a Bungie application. 1248 1249 Parameters 1250 ----------- 1251 appid: `int` 1252 The application id. 1253 1254 Returns 1255 -------- 1256 `aiobungie.crates.Application` 1257 A Bungie application. 1258 """ 1259 resp = await self.rest.fetch_application(appid) 1260 1261 return self.factory.deserialize_app(resp)
Fetch a Bungie application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.crates.Application: A Bungie application.
1265 async def fetch_public_milestone_content( 1266 self, milestone_hash: int, / 1267 ) -> milestones.MilestoneContent: 1268 """Fetch the milestone content given its hash. 1269 1270 Parameters 1271 ---------- 1272 milestone_hash : `int` 1273 The milestone hash. 1274 1275 Returns 1276 ------- 1277 `aiobungie.crates.milestones.MilestoneContent` 1278 A milestone content object. 1279 """ 1280 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1281 1282 return self.factory.deserialize_public_milestone_content(resp)
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.crates.milestones.MilestoneContent: A milestone content object.
782@typing.final 783class ClosedReasons(Flag): 784 """A Flags enumeration representing the reasons why a person can't join this user's fireteam.""" 785 786 NONE = 0 787 MATCHMAKING = 1 788 LOADING = 2 789 SOLO = 4 790 """The activity is required to be played solo.""" 791 INTERNAL_REASONS = 8 792 """ 793 The user can't be joined for one of a variety of internal reasons. 794 Basically, the game can't let you join at this time, 795 but for reasons that aren't under the control of this user 796 """ 797 DISALLOWED_BY_GAME_STATE = 16 798 """The user's current activity/quest/other transitory game state is preventing joining.""" 799 OFFLINE = 32768 800 """The user appears offline."""
A Flags enumeration representing the reasons why a person can't join this user's fireteam.
The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user
The user's current activity/quest/other transitory game state is preventing joining.
74@typing.final 75class ComponentFields(enums.Enum): 76 """An enum that provides fields found in a base component response.""" 77 78 PRIVACY = ComponentPrivacy 79 DISABLED = False
An enum that provides fields found in a base component response.
65@typing.final 66class ComponentPrivacy(int, enums.Enum): 67 """An enum the provides privacy settings for profile components.""" 68 69 NONE = 0 70 PUBLIC = 1 71 PRIVATE = 2
An enum the provides privacy settings for profile components.
363@typing.final 364class ComponentType(Enum): 365 """An Enum for Destiny 2 profile Components.""" 366 367 NONE = 0 368 369 PROFILE = 100 370 PROFILE_INVENTORIES = 102 371 PROFILE_CURRENCIES = 103 372 PROFILE_PROGRESSION = 104 373 ALL_PROFILES = ( 374 PROFILE, 375 PROFILE_INVENTORIES, 376 PROFILE_CURRENCIES, 377 PROFILE_PROGRESSION, 378 ) 379 """All profile components.""" 380 381 VENDORS = 400 382 VENDOR_SALES = 402 383 VENDOR_RECEIPTS = 101 384 ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES) 385 """All vendor components.""" 386 387 # Items 388 ITEM_INSTANCES = 300 389 ITEM_OBJECTIVES = 301 390 ITEM_PERKS = 302 391 ITEM_RENDER_DATA = 303 392 ITEM_STATS = 304 393 ITEM_SOCKETS = 305 394 ITEM_TALENT_GRINDS = 306 395 ITEM_PLUG_STATES = 308 396 ITEM_PLUG_OBJECTIVES = 309 397 ITEM_REUSABLE_PLUGS = 310 398 399 ALL_ITEMS = ( 400 ITEM_PLUG_OBJECTIVES, 401 ITEM_PLUG_STATES, 402 ITEM_SOCKETS, 403 ITEM_INSTANCES, 404 ITEM_OBJECTIVES, 405 ITEM_PERKS, 406 ITEM_RENDER_DATA, 407 ITEM_STATS, 408 ITEM_TALENT_GRINDS, 409 ITEM_REUSABLE_PLUGS, 410 ) 411 """All item components.""" 412 413 PLATFORM_SILVER = 105 414 KIOSKS = 500 415 CURRENCY_LOOKUPS = 600 416 PRESENTATION_NODES = 700 417 COLLECTIBLES = 800 418 RECORDS = 900 419 TRANSITORY = 1000 420 METRICS = 1100 421 INVENTORIES = 102 422 STRING_VARIABLES = 1200 423 CRAFTABLES = 1300 424 425 CHARACTERS = 200 426 CHARACTER_INVENTORY = 201 427 CHARECTER_PROGRESSION = 202 428 CHARACTER_RENDER_DATA = 203 429 CHARACTER_ACTIVITIES = 204 430 CHARACTER_EQUIPMENT = 205 431 432 ALL_CHARACTERS = ( 433 CHARACTERS, 434 CHARACTER_INVENTORY, 435 CHARECTER_PROGRESSION, 436 CHARACTER_RENDER_DATA, 437 CHARACTER_ACTIVITIES, 438 CHARACTER_EQUIPMENT, 439 RECORDS, 440 ) 441 """All character components.""" 442 443 ALL = ( 444 *ALL_PROFILES, # type: ignore 445 *ALL_CHARACTERS, # type: ignore 446 *ALL_VENDORS, # type: ignore 447 *ALL_ITEMS, # type: ignore 448 RECORDS, 449 CURRENCY_LOOKUPS, 450 PRESENTATION_NODES, 451 COLLECTIBLES, 452 KIOSKS, 453 METRICS, 454 PLATFORM_SILVER, 455 INVENTORIES, 456 STRING_VARIABLES, 457 TRANSITORY, 458 CRAFTABLES, 459 ) 460 """ALl components included."""
An Enum for Destiny 2 profile Components.
All item components.
All character components.
ALl components included.
664@typing.final 665class CredentialType(int, Enum): 666 """The types of the accounts system supports at bungie.""" 667 668 NONE = 0 669 XUID = 1 670 PSNID = 2 671 WILD = 3 672 FAKE = 4 673 FACEBOOK = 5 674 GOOGLE = 8 675 WINDOWS = 9 676 DEMONID = 10 677 STEAMID = 12 678 BATTLENETID = 14 679 STADIAID = 16 680 TWITCHID = 18
The types of the accounts system supports at bungie.
542@typing.final 543class DamageType(int, Enum): 544 """Enums for Destiny Damage types""" 545 546 NONE = 0 547 KINETIC = 1 548 ARC = 2 549 SOLAR = 3 550 VOID = 4 551 RAID = 5 552 """This is a special damage type reserved for some raid activity encounters.""" 553 STASIS = 6
Enums for Destiny Damage types
This is a special damage type reserved for some raid activity encounters.
65@typing.final 66class Difficulty(int, enums.Enum): 67 """An enum for activities difficulties.""" 68 69 TRIVIAL = 0 70 EASY = 1 71 NORMAL = 2 72 CHALLENGING = 3 73 HARD = 4 74 BRAVE = 5 75 ALMOST_IMPOSSIBLE = 6 76 IMPOSSIBLE = 7
An enum for activities difficulties.
165@typing.final 166class Dungeon(int, Enum): 167 """An Enum for all available Dungeon/Like missions in Destiny 2.""" 168 169 NORMAL_PRESAGE = 2124066889 170 """Normal Presage""" 171 172 MASTER_PRESAGE = 4212753278 173 """Master Presage""" 174 175 HARBINGER = 1738383283 176 """Harbinger""" 177 178 PROPHECY = 4148187374 179 """Prophecy""" 180 181 MASTER_POH = 785700673 182 """Master Pit of Heresy?""" 183 184 LEGEND_POH = 785700678 185 """Legend Pit of Heresy?""" 186 187 POH = 1375089621 188 """Normal Pit of Heresy.""" 189 190 SHATTERED = 2032534090 191 """Shattered Throne""" 192 193 GOA_LEGEND = 4078656646 194 """Grasp of Avarice legend.""" 195 196 GOA_MASTER = 3774021532 197 """Grasp of Avarice master."""
An Enum for all available Dungeon/Like missions in Destiny 2.
77class Enum(__enum.Enum): 78 """Builtin Python enum with extra handlings.""" 79 80 @property 81 def name(self) -> str: # type: ignore[override] 82 return self._name_ 83 84 @property 85 def value(self) -> typing.Any: # type: ignore[override] 86 return self._value_ 87 88 def __str__(self) -> str: 89 return self._name_ 90 91 def __repr__(self) -> str: 92 return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>" 93 94 def __int__(self) -> int: 95 if isinstance(self.value, _ITERABLE): 96 raise TypeError( 97 f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.", 98 ) 99 return int(self.value)
Builtin Python enum with extra handlings.
61class Factory(interfaces.FactoryInterface): 62 """The base deserialization factory class for all aiobungie objects. 63 64 Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them 65 into a `aiobungie.crates` Python classes. 66 """ 67 68 __slots__ = ("_net",) 69 70 def __init__(self, net: traits.Netrunner) -> None: 71 self._net = net 72 73 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 74 return user.BungieUser( 75 id=int(data["membershipId"]), 76 created_at=time.clean_date(data["firstAccess"]), 77 name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined), 78 is_deleted=data["isDeleted"], 79 about=data["about"], 80 updated_at=time.clean_date(data["lastUpdate"]), 81 psn_name=data.get("psnDisplayName", None), 82 stadia_name=data.get("stadiaDisplayName", None), 83 steam_name=data.get("steamDisplayName", None), 84 twitch_name=data.get("twitchDisplayName", None), 85 blizzard_name=data.get("blizzardDisplayName", None), 86 status=data["statusText"], 87 locale=data["locale"], 88 picture=assets.Image(path=str(data["profilePicturePath"])), 89 code=data.get("cachedBungieGlobalDisplayNameCode", None), 90 unique_name=data.get("uniqueName", None), 91 theme_id=int(data["profileTheme"]), 92 show_activity=bool(data["showActivity"]), 93 theme_name=data["profileThemeName"], 94 display_title=data["userTitleDisplay"], 95 ) 96 97 def deserialize_partial_bungie_user( 98 self, payload: typedefs.JSONObject 99 ) -> user.PartialBungieUser: 100 return user.PartialBungieUser( 101 net=self._net, 102 types=[ 103 enums.MembershipType(type_) 104 for type_ in payload.get("applicableMembershipTypes", []) 105 ], 106 name=payload.get("displayName", undefined.Undefined), 107 id=int(payload["membershipId"]), 108 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 109 is_public=payload["isPublic"], 110 icon=assets.Image(payload.get("iconPath", "")), 111 type=enums.MembershipType(payload["membershipType"]), 112 ) 113 114 def deserialize_destiny_membership( 115 self, payload: typedefs.JSONObject 116 ) -> user.DestinyMembership: 117 name: undefined.UndefinedOr[str] = undefined.Undefined 118 if ( 119 raw_name := payload.get("bungieGlobalDisplayName", "") 120 ) and not typedefs.is_unknown(raw_name): 121 name = raw_name 122 123 return user.DestinyMembership( 124 net=self._net, 125 id=int(payload["membershipId"]), 126 name=name, 127 code=payload.get("bungieGlobalDisplayNameCode", None), 128 last_seen_name=payload.get("LastSeenDisplayName") 129 or payload.get("displayName") # noqa: W503 130 or "", # noqa: W503 131 type=enums.MembershipType(payload["membershipType"]), 132 is_public=payload["isPublic"], 133 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 134 icon=assets.Image(payload.get("iconPath", "")), 135 types=[ 136 enums.MembershipType(type_) 137 for type_ in payload.get("applicableMembershipTypes", []) 138 ], 139 ) 140 141 def deserialize_destiny_memberships( 142 self, data: typedefs.JSONArray 143 ) -> collections.Sequence[user.DestinyMembership]: 144 return [self.deserialize_destiny_membership(membership) for membership in data] 145 146 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 147 148 primary_membership_id: typing.Optional[int] = None 149 if raw_primary_id := data.get("primaryMembershipId"): 150 primary_membership_id = int(raw_primary_id) 151 152 return user.User( 153 bungie=self.deserialize_bungie_user(data["bungieNetUser"]), 154 destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]), 155 primary_membership_id=primary_membership_id, 156 ) 157 158 def deserialize_searched_user( 159 self, payload: typedefs.JSONObject 160 ) -> user.SearchableDestinyUser: 161 name: undefined.UndefinedOr[str] = undefined.Undefined 162 if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown( 163 raw_name 164 ): 165 name = raw_name 166 167 code: typing.Optional[int] = None 168 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 169 code = int(raw_code) 170 171 bungie_id: typing.Optional[int] = None 172 if raw_bungie_id := payload.get("bungieNetMembershipId"): 173 bungie_id = int(raw_bungie_id) 174 175 return user.SearchableDestinyUser( 176 name=name, 177 code=code, 178 bungie_id=bungie_id, 179 memberships=self.deserialize_destiny_memberships( 180 payload["destinyMemberships"] 181 ), 182 ) 183 184 def deserialize_user_credentials( 185 self, payload: typedefs.JSONArray 186 ) -> collections.Sequence[user.UserCredentials]: 187 return [ 188 user.UserCredentials( 189 type=enums.CredentialType(int(creds["credentialType"])), 190 display_name=creds["credentialDisplayName"], 191 is_public=creds["isPublic"], 192 self_as_string=creds.get("credentialAsString", undefined.Undefined), 193 ) 194 for creds in payload 195 ] 196 197 @staticmethod 198 def set_themese_attrs( 199 payload: typedefs.JSONArray, / 200 ) -> typing.Collection[user.UserThemes]: 201 return [ 202 user.UserThemes( 203 id=int(entry["userThemeId"]), 204 name=entry["userThemeName"] 205 if "userThemeName" in entry 206 else undefined.Undefined, 207 description=entry["userThemeDescription"] 208 if "userThemeDescription" in entry 209 else undefined.Undefined, 210 ) 211 for entry in payload 212 ] 213 214 def deserialize_user_themes( 215 self, payload: typedefs.JSONArray 216 ) -> collections.Sequence[user.UserThemes]: 217 return list(self.set_themese_attrs(payload)) 218 219 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 220 221 # This is kinda redundant 222 data = payload 223 224 # This is always outside the details. 225 current_user_map: typing.Optional[ 226 collections.Mapping[str, clans.ClanMember] 227 ] = None 228 if raw_current_user_map := payload.get("currentUserMemberMap"): 229 current_user_map = { 230 membership_type: self.deserialize_clan_member(membership) 231 for membership_type, membership in raw_current_user_map.items() 232 } 233 234 try: 235 data = payload["detail"] 236 except KeyError: 237 pass 238 239 id = data["groupId"] 240 name = data["name"] 241 created_at = data["creationDate"] 242 member_count = data["memberCount"] 243 about = data["about"] 244 motto = data["motto"] 245 is_public = data["isPublic"] 246 banner = assets.Image(str(data["bannerPath"])) 247 avatar = assets.Image(str(data["avatarPath"])) 248 tags = data["tags"] 249 type = data["groupType"] 250 251 features = data["features"] 252 features_obj = clans.ClanFeatures( 253 max_members=features["maximumMembers"], 254 max_membership_types=features["maximumMembershipsOfGroupType"], 255 capabilities=features["capabilities"], 256 membership_types=features["membershipTypes"], 257 invite_permissions=features["invitePermissionOverride"], 258 update_banner_permissions=features["updateBannerPermissionOverride"], 259 update_culture_permissions=features["updateCulturePermissionOverride"], 260 join_level=features["joinLevel"], 261 ) 262 263 information: typedefs.JSONObject = data["clanInfo"] 264 progression: collections.Mapping[int, progressions.Progression] = { 265 int(prog_hash): self.deserialize_progressions(prog) 266 for prog_hash, prog in information["d2ClanProgressions"].items() 267 } 268 269 founder: typedefs.NoneOr[clans.ClanMember] = None 270 if raw_founder := payload.get("founder"): 271 founder = self.deserialize_clan_member(raw_founder) 272 273 return clans.Clan( 274 net=self._net, 275 id=int(id), 276 name=name, 277 type=enums.GroupType(type), 278 created_at=time.clean_date(created_at), 279 member_count=member_count, 280 motto=motto, 281 about=about, 282 is_public=is_public, 283 banner=banner, 284 avatar=avatar, 285 tags=tags, 286 features=features_obj, 287 owner=founder, 288 progressions=progression, 289 call_sign=information["clanCallsign"], 290 banner_data=information["clanBannerData"], 291 chat_security=data["chatSecurity"], 292 conversation_id=int(data["conversationId"]), 293 allow_chat=data["allowChat"], 294 theme=data["theme"], 295 current_user_membership=current_user_map, 296 ) 297 298 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 299 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 300 return clans.ClanMember( 301 net=self._net, 302 last_seen_name=destiny_user.last_seen_name, 303 id=destiny_user.id, 304 name=destiny_user.name, 305 icon=destiny_user.icon, 306 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 307 group_id=int(data["groupId"]), 308 joined_at=time.clean_date(data["joinDate"]), 309 types=destiny_user.types, 310 is_public=destiny_user.is_public, 311 type=destiny_user.type, 312 code=destiny_user.code, 313 is_online=data["isOnline"], 314 crossave_override=destiny_user.crossave_override, 315 bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 316 if "bungieNetUserInfo" in data 317 else None, 318 member_type=enums.ClanMemberType(int(data["memberType"])), 319 ) 320 321 def deserialize_clan_members( 322 self, data: typedefs.JSONObject, / 323 ) -> iterators.FlatIterator[clans.ClanMember]: 324 return iterators.FlatIterator( 325 [self.deserialize_clan_member(member) for member in data["results"]] 326 ) 327 328 def deserialize_group_member( 329 self, payload: typedefs.JSONObject 330 ) -> clans.GroupMember: 331 member = payload["member"] 332 return clans.GroupMember( 333 net=self._net, 334 join_date=time.clean_date(member["joinDate"]), 335 group_id=int(member["groupId"]), 336 member_type=enums.ClanMemberType(member["memberType"]), 337 is_online=member["isOnline"], 338 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 339 inactive_memberships=payload.get("areAllMembershipsInactive", None), 340 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 341 group=self.deserialize_clan(payload["group"]), 342 ) 343 344 def _deserialize_clan_conversation( 345 self, payload: typedefs.JSONObject 346 ) -> clans.ClanConversation: 347 return clans.ClanConversation( 348 net=self._net, 349 id=int(payload["conversationId"]), 350 group_id=int(payload["groupId"]), 351 name=( 352 payload["chatName"] 353 if not typedefs.is_unknown(payload["chatName"]) 354 else undefined.Undefined 355 ), 356 chat_enabled=payload["chatEnabled"], 357 security=payload["chatSecurity"], 358 ) 359 360 def deserialize_clan_conversations( 361 self, payload: typedefs.JSONArray 362 ) -> collections.Sequence[clans.ClanConversation]: 363 return [self._deserialize_clan_conversation(conv) for conv in payload] 364 365 def deserialize_app_owner( 366 self, payload: typedefs.JSONObject 367 ) -> application.ApplicationOwner: 368 return application.ApplicationOwner( 369 net=self._net, 370 name=payload.get("bungieGlobalDisplayName", undefined.Undefined), 371 id=int(payload["membershipId"]), 372 type=enums.MembershipType(payload["membershipType"]), 373 icon=assets.Image(str(payload["iconPath"])), 374 is_public=payload["isPublic"], 375 code=payload.get("bungieGlobalDisplayNameCode", None), 376 ) 377 378 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 379 return application.Application( 380 id=int(payload["applicationId"]), 381 name=payload["name"], 382 link=payload["link"], 383 status=payload["status"], 384 redirect_url=payload.get("redirectUrl", None), 385 created_at=time.clean_date(str(payload["creationDate"])), 386 published_at=time.clean_date(str(payload["firstPublished"])), 387 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 388 scope=payload.get("scope", undefined.Undefined), 389 ) 390 391 def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character: 392 total_time = time.format_played(int(payload["minutesPlayedTotal"]), suffix=True) 393 return character.Character( 394 net=self._net, 395 id=int(payload["characterId"]), 396 gender=enums.Gender(payload["genderType"]), 397 race=enums.Race(payload["raceType"]), 398 class_type=enums.Class(payload["classType"]), 399 emblem=assets.Image(str(payload["emblemBackgroundPath"])), 400 emblem_icon=assets.Image(str(payload["emblemPath"])), 401 emblem_hash=int(payload["emblemHash"]), 402 last_played=time.clean_date(payload["dateLastPlayed"]), 403 total_played_time=total_time, 404 member_id=int(payload["membershipId"]), 405 member_type=enums.MembershipType(payload["membershipType"]), 406 level=payload["baseCharacterLevel"], 407 title_hash=payload.get("titleRecordHash", None), 408 light=payload["light"], 409 stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()}, 410 ) 411 412 def deserialize_profile( 413 self, payload: typedefs.JSONObject, / 414 ) -> typing.Optional[profile.Profile]: 415 if (raw_profile := payload.get("data")) is None: 416 return None 417 418 payload = raw_profile 419 id = int(payload["userInfo"]["membershipId"]) 420 name = payload["userInfo"]["displayName"] 421 is_public = payload["userInfo"]["isPublic"] 422 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 423 last_played = time.clean_date(str(payload["dateLastPlayed"])) 424 character_ids = [int(cid) for cid in payload["characterIds"]] 425 power_cap = payload["currentSeasonRewardPowerCap"] 426 427 return profile.Profile( 428 id=int(id), 429 name=name, 430 is_public=is_public, 431 type=type, 432 last_played=last_played, 433 character_ids=character_ids, 434 power_cap=power_cap, 435 net=self._net, 436 ) 437 438 def deserialize_profile_item( 439 self, payload: typedefs.JSONObject 440 ) -> profile.ProfileItemImpl: 441 442 instance_id: typing.Optional[int] = None 443 if raw_instance_id := payload.get("itemInstanceId"): 444 instance_id = int(raw_instance_id) 445 446 version_number: typing.Optional[int] = None 447 if raw_version := payload.get("versionNumber"): 448 version_number = int(raw_version) 449 450 transfer_status = enums.TransferStatus(payload["transferStatus"]) 451 452 return profile.ProfileItemImpl( 453 net=self._net, 454 hash=payload["itemHash"], 455 quantity=payload["quantity"], 456 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 457 location=enums.ItemLocation(payload["location"]), 458 bucket=payload["bucketHash"], 459 transfer_status=transfer_status, 460 lockable=payload["lockable"], 461 state=enums.ItemState(payload["state"]), 462 dismantel_permissions=payload["dismantlePermission"], 463 is_wrapper=payload["isWrapper"], 464 instance_id=instance_id, 465 version_number=version_number, 466 ornament_id=payload.get("overrideStyleItemHash"), 467 ) 468 469 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 470 return records.Objective( 471 net=self._net, 472 hash=payload["objectiveHash"], 473 visible=payload["visible"], 474 complete=payload["complete"], 475 completion_value=payload["completionValue"], 476 progress=payload.get("progress"), 477 destination_hash=payload.get("destinationHash"), 478 activity_hash=payload.get("activityHash"), 479 ) 480 481 def deserialize_records( 482 self, 483 payload: typedefs.JSONObject, 484 scores: typing.Optional[records.RecordScores] = None, 485 **nodes: int, 486 ) -> records.Record: 487 objectives: typing.Optional[list[records.Objective]] = None 488 interval_objectives: typing.Optional[list[records.Objective]] = None 489 record_state: typedefs.IntAnd[records.RecordState] 490 491 record_state = records.RecordState(payload["state"]) 492 493 if raw_objs := payload.get("objectives"): 494 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 495 496 if raw_interval_objs := payload.get("intervalObjectives"): 497 interval_objectives = [ 498 self.deserialize_objectives(obj) for obj in raw_interval_objs 499 ] 500 501 return records.Record( 502 scores=scores, 503 categories_node_hash=nodes.get("categories_hash", undefined.Undefined), 504 seals_node_hash=nodes.get("seals_hash", undefined.Undefined), 505 state=record_state, 506 objectives=objectives, 507 interval_objectives=interval_objectives, 508 redeemed_count=payload.get("intervalsRedeemedCount", 0), 509 completion_times=payload.get("completedCount", None), 510 reward_visibility=payload.get("rewardVisibilty", None), 511 ) 512 513 def deserialize_character_records( 514 self, 515 payload: typedefs.JSONObject, 516 scores: typing.Optional[records.RecordScores] = None, 517 record_hashes: typing.Optional[list[int]] = None, 518 ) -> records.CharacterRecord: 519 520 record = self.deserialize_records(payload, scores) 521 return records.CharacterRecord( 522 scores=scores, 523 categories_node_hash=record.categories_node_hash, 524 seals_node_hash=record.seals_node_hash, 525 state=record.state, 526 objectives=record.objectives, 527 interval_objectives=record.interval_objectives, 528 redeemed_count=payload.get("intervalsRedeemedCount", 0), 529 completion_times=payload.get("completedCount"), 530 reward_visibility=payload.get("rewardVisibilty"), 531 record_hashes=record_hashes or [], 532 ) 533 534 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 535 return character.Dye( 536 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 537 ) 538 539 def deserialize_character_customization( 540 self, payload: typedefs.JSONObject 541 ) -> character.CustomizationOptions: 542 return character.CustomizationOptions( 543 personality=payload["personality"], 544 face=payload["face"], 545 skin_color=payload["skinColor"], 546 lip_color=payload["lipColor"], 547 eye_color=payload["eyeColor"], 548 hair_colors=payload.get("hairColors", []), 549 feature_colors=payload.get("featureColors", []), 550 decal_color=payload["decalColor"], 551 wear_helmet=payload["wearHelmet"], 552 hair_index=payload["hairIndex"], 553 feature_index=payload["featureIndex"], 554 decal_index=payload["decalIndex"], 555 ) 556 557 def deserialize_character_minimal_equipments( 558 self, payload: typedefs.JSONObject 559 ) -> character.MinimalEquipments: 560 dyes = None 561 if raw_dyes := payload.get("dyes"): 562 if raw_dyes: 563 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 564 return character.MinimalEquipments( 565 net=self._net, item_hash=payload["itemHash"], dyes=dyes 566 ) 567 568 def deserialize_character_render_data( 569 self, payload: typedefs.JSONObject, / 570 ) -> character.RenderedData: 571 return character.RenderedData( 572 net=self._net, 573 customization=self.deserialize_character_customization( 574 payload["customization"] 575 ), 576 custom_dyes=[ 577 self.deserialize_character_dye(dye) 578 for dye in payload["customDyes"] 579 if dye 580 ], 581 equipment=[ 582 self.deserialize_character_minimal_equipments(equipment) 583 for equipment in payload["peerView"]["equipment"] 584 ], 585 ) 586 587 def deserialize_available_activity( 588 self, payload: typedefs.JSONObject 589 ) -> activity.AvailableActivity: 590 return activity.AvailableActivity( 591 hash=payload["activityHash"], 592 is_new=payload["isNew"], 593 is_completed=payload["isCompleted"], 594 is_visible=payload["isVisible"], 595 display_level=payload.get("displayLevel"), 596 recommended_light=payload.get("recommendedLight"), 597 difficulty=activity.Difficulty(payload["difficultyTier"]), 598 can_join=payload["canJoin"], 599 can_lead=payload["canLead"], 600 ) 601 602 def deserialize_character_activity( 603 self, payload: typedefs.JSONObject 604 ) -> activity.CharacterActivity: 605 current_mode: typing.Optional[enums.GameMode] = None 606 if raw_current_mode := payload.get("currentActivityModeType"): 607 current_mode = enums.GameMode(raw_current_mode) 608 609 current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None 610 if raw_current_modes := payload.get("currentActivityModeTypes"): 611 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 612 613 return activity.CharacterActivity( 614 date_started=time.clean_date(payload["dateActivityStarted"]), 615 current_hash=payload["currentActivityHash"], 616 current_mode_hash=payload["currentActivityModeHash"], 617 current_mode=current_mode, 618 current_mode_hashes=payload.get("currentActivityModeHashes"), 619 current_mode_types=current_mode_types, 620 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 621 last_story_hash=payload["lastCompletedStoryHash"], 622 available_activities=[ 623 self.deserialize_available_activity(activity_) 624 for activity_ in payload["availableActivities"] 625 ], 626 ) 627 628 def deserialize_profile_items( 629 self, payload: typedefs.JSONObject, / 630 ) -> list[profile.ProfileItemImpl]: 631 return [self.deserialize_profile_item(item) for item in payload["items"]] 632 633 def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node: 634 return records.Node( 635 state=int(payload["state"]), 636 objective=self.deserialize_objectives(payload["objective"]) 637 if "objective" in payload 638 else None, 639 progress_value=int(payload["progressValue"]), 640 completion_value=int(payload["completionValue"]), 641 record_category_score=int(payload["recordCategoryScore"]) 642 if "recordCategoryScore" in payload 643 else None, 644 ) 645 646 @staticmethod 647 def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible: 648 recent_collectibles: typing.Optional[collections.Collection[int]] = None 649 if raw_recent_collectibles := payload.get("recentCollectibleHashes"): 650 recent_collectibles = [ 651 int(item_hash) for item_hash in raw_recent_collectibles 652 ] 653 654 collectibles: dict[int, int] = {} 655 for item_hash, mapping in payload["collectibles"].items(): 656 collectibles[int(item_hash)] = int(mapping["state"]) 657 658 return items.Collectible( 659 recent_collectibles=recent_collectibles, 660 collectibles=collectibles, 661 collection_categorie_hash=int(payload["collectionCategoriesRootNodeHash"]), 662 collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]), 663 ) 664 665 @staticmethod 666 def _deserialize_currencies( 667 payload: typedefs.JSONObject, 668 ) -> collections.Sequence[items.Currency]: 669 return [ 670 items.Currency(hash=int(item_hash), amount=int(amount)) 671 for item_hash, amount in payload["itemQuantities"].items() 672 ] 673 674 def deserialize_progressions( 675 self, payload: typedefs.JSONObject 676 ) -> progressions.Progression: 677 return progressions.Progression( 678 hash=int(payload["progressionHash"]), 679 level=int(payload["level"]), 680 cap=int(payload["levelCap"]), 681 daily_limit=int(payload["dailyLimit"]), 682 weekly_limit=int(payload["weeklyLimit"]), 683 current_progress=int(payload["currentProgress"]), 684 daily_progress=int(payload["dailyProgress"]), 685 needed=int(payload["progressToNextLevel"]), 686 next_level=int(payload["nextLevelAt"]), 687 ) 688 689 def _deserialize_factions( 690 self, payload: typedefs.JSONObject 691 ) -> progressions.Factions: 692 progs = self.deserialize_progressions(payload) 693 return progressions.Factions( 694 hash=progs.hash, 695 level=progs.level, 696 cap=progs.cap, 697 daily_limit=progs.daily_limit, 698 weekly_limit=progs.weekly_limit, 699 current_progress=progs.current_progress, 700 daily_progress=progs.daily_progress, 701 needed=progs.needed, 702 next_level=progs.next_level, 703 faction_hash=payload["factionHash"], 704 faction_vendor_hash=payload["factionVendorIndex"], 705 ) 706 707 def _deserialize_milestone_available_quest( 708 self, payload: typedefs.JSONObject 709 ) -> milestones.MilestoneQuest: 710 return milestones.MilestoneQuest( 711 item_hash=payload["questItemHash"], 712 status=self._deserialize_milestone_quest_status(payload["status"]), 713 ) 714 715 def _deserialize_milestone_activity( 716 self, payload: typedefs.JSONObject 717 ) -> milestones.MilestoneActivity: 718 719 phases: typing.Optional[ 720 collections.Sequence[milestones.MilestoneActivityPhase] 721 ] = None 722 if raw_phases := payload.get("phases"): 723 phases = [ 724 milestones.MilestoneActivityPhase( 725 is_completed=obj["complete"], hash=obj["phaseHash"] 726 ) 727 for obj in raw_phases 728 ] 729 730 return milestones.MilestoneActivity( 731 hash=payload["activityHash"], 732 challenges=[ 733 self.deserialize_objectives(obj["objective"]) 734 for obj in payload["challenges"] 735 ], 736 modifier_hashes=payload.get("modifierHashes"), 737 boolean_options=payload.get("booleanActivityOptions"), 738 phases=phases, 739 ) 740 741 def _deserialize_milestone_quest_status( 742 self, payload: typedefs.JSONObject 743 ) -> milestones.QuestStatus: 744 return milestones.QuestStatus( 745 net=self._net, 746 quest_hash=payload["questHash"], 747 step_hash=payload["stepHash"], 748 step_objectives=[ 749 self.deserialize_objectives(objective) 750 for objective in payload["stepObjectives"] 751 ], 752 is_tracked=payload["tracked"], 753 is_completed=payload["completed"], 754 started=payload["started"], 755 item_instance_id=payload["itemInstanceId"], 756 vendor_hash=payload.get("vendorHash"), 757 is_redeemed=payload["redeemed"], 758 ) 759 760 def _deserialize_milestone_rewards( 761 self, payload: typedefs.JSONObject 762 ) -> milestones.MilestoneReward: 763 return milestones.MilestoneReward( 764 category_hash=payload["rewardCategoryHash"], 765 entries=[ 766 milestones.MilestoneRewardEntry( 767 entry_hash=entry["rewardEntryHash"], 768 is_earned=entry["earned"], 769 is_redeemed=entry["redeemed"], 770 ) 771 for entry in payload["entries"] 772 ], 773 ) 774 775 def deserialize_milestone( 776 self, payload: typedefs.JSONObject 777 ) -> milestones.Milestone: 778 start_date: typing.Optional[datetime.datetime] = None 779 if raw_start_date := payload.get("startDate"): 780 start_date = time.clean_date(raw_start_date) 781 782 end_date: typing.Optional[datetime.datetime] = None 783 if raw_end_date := payload.get("endDate"): 784 end_date = time.clean_date(raw_end_date) 785 786 rewards: typing.Optional[ 787 collections.Collection[milestones.MilestoneReward] 788 ] = None 789 if raw_rewards := payload.get("rewards"): 790 rewards = [ 791 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 792 ] 793 794 activities: typing.Optional[ 795 collections.Sequence[milestones.MilestoneActivity] 796 ] = None 797 if raw_activities := payload.get("activities"): 798 activities = [ 799 self._deserialize_milestone_activity(active) 800 for active in raw_activities 801 ] 802 803 quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None 804 if raw_quests := payload.get("availableQuests"): 805 quests = [ 806 self._deserialize_milestone_available_quest(quest) 807 for quest in raw_quests 808 ] 809 810 vendors: typing.Optional[ 811 collections.Sequence[milestones.MilestoneVendor] 812 ] = None 813 if raw_vendors := payload.get("vendors"): 814 vendors = [ 815 milestones.MilestoneVendor( 816 vendor_hash=vendor["vendorHash"], 817 preview_itemhash=vendor.get("previewItemHash"), 818 ) 819 for vendor in raw_vendors 820 ] 821 822 return milestones.Milestone( 823 hash=payload["milestoneHash"], 824 start_date=start_date, 825 end_date=end_date, 826 order=payload["order"], 827 rewards=rewards, 828 available_quests=quests, 829 activities=activities, 830 vendors=vendors, 831 ) 832 833 def _deserialize_artifact_tiers( 834 self, payload: typedefs.JSONObject 835 ) -> season.ArtifactTier: 836 return season.ArtifactTier( 837 hash=payload["tierHash"], 838 is_unlocked=payload["isUnlocked"], 839 points_to_unlock=payload["pointsToUnlock"], 840 items=[ 841 season.ArtifactTierItem( 842 hash=item["itemHash"], is_active=item["isActive"] 843 ) 844 for item in payload["items"] 845 ], 846 ) 847 848 def deserialize_characters( 849 self, payload: typedefs.JSONObject 850 ) -> collections.Mapping[int, character.Character]: 851 return { 852 int(char_id): self._set_character_attrs(char) 853 for char_id, char in payload["data"].items() 854 } 855 856 def deserialize_character( 857 self, payload: typedefs.JSONObject 858 ) -> character.Character: 859 return self._set_character_attrs(payload) 860 861 def deserialize_character_equipments( 862 self, payload: typedefs.JSONObject 863 ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]: 864 return { 865 int(char_id): self.deserialize_profile_items(item) 866 for char_id, item in payload["data"].items() 867 } 868 869 def deserialize_character_activities( 870 self, payload: typedefs.JSONObject 871 ) -> collections.Mapping[int, activity.CharacterActivity]: 872 return { 873 int(char_id): self.deserialize_character_activity(data) 874 for char_id, data in payload["data"].items() 875 } 876 877 def deserialize_characters_render_data( 878 self, payload: typedefs.JSONObject 879 ) -> collections.Mapping[int, character.RenderedData]: 880 return { 881 int(char_id): self.deserialize_character_render_data(data) 882 for char_id, data in payload["data"].items() 883 } 884 885 def deserialize_character_progressions( 886 self, payload: typedefs.JSONObject 887 ) -> character.CharacterProgression: 888 progressions_ = { 889 int(prog_id): self.deserialize_progressions(prog) 890 for prog_id, prog in payload["progressions"].items() 891 } 892 893 factions = { 894 int(faction_id): self._deserialize_factions(faction) 895 for faction_id, faction in payload["factions"].items() 896 } 897 898 milestones_ = { 899 int(milestone_hash): self.deserialize_milestone(milestone) 900 for milestone_hash, milestone in payload["milestones"].items() 901 } 902 903 uninstanced_item_objectives = { 904 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 905 for item_hash, obj in payload["uninstancedItemObjectives"].items() 906 } 907 908 artifact = payload["seasonalArtifact"] 909 seasonal_artifact = season.CharacterScopedArtifact( 910 hash=artifact["artifactHash"], 911 points_used=artifact["pointsUsed"], 912 reset_count=artifact["resetCount"], 913 tiers=[ 914 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 915 ], 916 ) 917 checklists = payload["checklists"] 918 919 return character.CharacterProgression( 920 progressions=progressions_, 921 factions=factions, 922 checklists=checklists, 923 milestones=milestones_, 924 seasonal_artifact=seasonal_artifact, 925 uninstanced_item_objectives=uninstanced_item_objectives, 926 ) 927 928 def deserialize_character_progressions_mapping( 929 self, payload: typedefs.JSONObject 930 ) -> collections.Mapping[int, character.CharacterProgression]: 931 character_progressions: collections.Mapping[ 932 int, character.CharacterProgression 933 ] = {} 934 for char_id, data in payload["data"].items(): 935 # A little hack to stop mypy complaining about Mapping <-> dict 936 character_progressions[int(char_id)] = self.deserialize_character_progressions(data) # type: ignore[index] 937 return character_progressions 938 939 def deserialize_characters_records( 940 self, 941 payload: typedefs.JSONObject, 942 ) -> collections.Mapping[int, records.CharacterRecord]: 943 944 return { 945 int(rec_id): self.deserialize_character_records( 946 rec, record_hashes=payload.get("featuredRecordHashes") 947 ) 948 for rec_id, rec in payload["records"].items() 949 } 950 951 def deserialize_profile_records( 952 self, payload: typedefs.JSONObject 953 ) -> collections.Mapping[int, records.Record]: 954 raw_profile_records = payload["data"] 955 scores = records.RecordScores( 956 current_score=raw_profile_records["score"], 957 legacy_score=raw_profile_records["legacyScore"], 958 lifetime_score=raw_profile_records["lifetimeScore"], 959 ) 960 return { 961 int(record_id): self.deserialize_records( 962 record, 963 scores, 964 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 965 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 966 ) 967 for record_id, record in raw_profile_records["records"].items() 968 } 969 970 def _deserialize_craftable_socket_plug( 971 self, payload: typedefs.JSONObject 972 ) -> items.CraftableSocketPlug: 973 return items.CraftableSocketPlug( 974 item_hash=int(payload["plugItemHash"]), 975 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 976 ) 977 978 def _deserialize_craftable_socket( 979 self, payload: typedefs.JSONObject 980 ) -> items.CraftableSocket: 981 982 plugs: list[items.CraftableSocketPlug] = [] 983 if raw_plug := payload.get("plug"): 984 plugs.extend( 985 self._deserialize_craftable_socket_plug(plug) for plug in raw_plug 986 ) 987 988 return items.CraftableSocket( 989 plug_set_hash=int(payload["plugSetHash"]), plugs=plugs 990 ) 991 992 def _deserialize_craftable_item( 993 self, payload: typedefs.JSONObject 994 ) -> items.CraftableItem: 995 996 return items.CraftableItem( 997 is_visible=payload["visible"], 998 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 999 sockets=[ 1000 self._deserialize_craftable_socket(socket) 1001 for socket in payload["sockets"] 1002 ], 1003 ) 1004 1005 def deserialize_craftables_component( 1006 self, payload: typedefs.JSONObject 1007 ) -> components.CraftablesComponent: 1008 return components.CraftablesComponent( 1009 net=self._net, 1010 craftables={ 1011 int(item_id): self._deserialize_craftable_item(item) 1012 for item_id, item in payload["craftables"].items() 1013 if item is not None 1014 }, 1015 crafting_root_node_hash=payload["craftingRootNodeHash"], 1016 ) 1017 1018 def deserialize_components( # noqa: C901 Too complex. 1019 self, payload: typedefs.JSONObject 1020 ) -> components.Component: 1021 1022 profile_: typing.Optional[profile.Profile] = None 1023 if raw_profile := payload.get("profile"): 1024 profile_ = self.deserialize_profile(raw_profile) 1025 1026 profile_progression: typing.Optional[profile.ProfileProgression] = None 1027 if raw_profile_progression := payload.get("profileProgression"): 1028 profile_progression = self.deserialize_profile_progression( 1029 raw_profile_progression 1030 ) 1031 1032 profile_currencies: typing.Optional[ 1033 collections.Sequence[profile.ProfileItemImpl] 1034 ] = None 1035 if raw_profile_currencies := payload.get("profileCurrencies"): 1036 if "data" in raw_profile_currencies: 1037 profile_currencies = self.deserialize_profile_items( 1038 raw_profile_currencies["data"] 1039 ) 1040 1041 profile_inventories: typing.Optional[ 1042 collections.Sequence[profile.ProfileItemImpl] 1043 ] = None 1044 if raw_profile_inventories := payload.get("profileInventory"): 1045 if "data" in raw_profile_inventories: 1046 profile_inventories = self.deserialize_profile_items( 1047 raw_profile_inventories["data"] 1048 ) 1049 1050 profile_records: typing.Optional[ 1051 collections.Mapping[int, records.Record] 1052 ] = None 1053 1054 if raw_profile_records_ := payload.get("profileRecords"): 1055 profile_records = self.deserialize_profile_records(raw_profile_records_) 1056 1057 characters: typing.Optional[typing.Mapping[int, character.Character]] = None 1058 if raw_characters := payload.get("characters"): 1059 characters = self.deserialize_characters(raw_characters) 1060 1061 character_records: typing.Optional[ 1062 collections.Mapping[int, records.CharacterRecord] 1063 ] = None 1064 1065 if raw_character_records := payload.get("characterRecords"): 1066 # Had to do it in two steps.. 1067 to_update: typedefs.JSONObject = {} 1068 for _, data in raw_character_records["data"].items(): 1069 for record_id, record in data.items(): 1070 to_update[record_id] = record 1071 1072 character_records = { 1073 int(rec_id): self.deserialize_character_records( 1074 rec, record_hashes=to_update.get("featuredRecordHashes") 1075 ) 1076 for rec_id, rec in to_update["records"].items() 1077 } 1078 1079 character_equipments: typing.Optional[ 1080 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1081 ] = None 1082 if raw_character_equips := payload.get("characterEquipment"): 1083 character_equipments = self.deserialize_character_equipments( 1084 raw_character_equips 1085 ) 1086 1087 character_inventories: typing.Optional[ 1088 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1089 ] = None 1090 if raw_character_inventories := payload.get("characterInventories"): 1091 if "data" in raw_character_inventories: 1092 character_inventories = self.deserialize_character_equipments( 1093 raw_character_inventories 1094 ) 1095 1096 character_activities: typing.Optional[ 1097 collections.Mapping[int, activity.CharacterActivity] 1098 ] = None 1099 if raw_char_acts := payload.get("characterActivities"): 1100 character_activities = self.deserialize_character_activities(raw_char_acts) 1101 1102 character_render_data: typing.Optional[ 1103 collections.Mapping[int, character.RenderedData] 1104 ] = None 1105 if raw_character_render_data := payload.get("characterRenderData"): 1106 character_render_data = self.deserialize_characters_render_data( 1107 raw_character_render_data 1108 ) 1109 1110 character_progressions: typing.Optional[ 1111 collections.Mapping[int, character.CharacterProgression] 1112 ] = None 1113 1114 if raw_character_progressions := payload.get("characterProgressions"): 1115 character_progressions = self.deserialize_character_progressions_mapping( 1116 raw_character_progressions 1117 ) 1118 1119 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1120 if raw_profile_string_vars := payload.get("profileStringVariables"): 1121 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1122 1123 character_string_vars: typing.Optional[ 1124 collections.Mapping[int, collections.Mapping[int, int]] 1125 ] = None 1126 if raw_character_string_vars := payload.get("characterStringVariables"): 1127 character_string_vars = { 1128 int(char_id): data["integerValuesByHash"] 1129 for char_id, data in raw_character_string_vars["data"].items() 1130 } 1131 1132 metrics: typing.Optional[ 1133 collections.Sequence[ 1134 collections.Mapping[ 1135 int, tuple[bool, typing.Optional[records.Objective]] 1136 ] 1137 ] 1138 ] = None 1139 root_node_hash: typing.Optional[int] = None 1140 1141 if raw_metrics := payload.get("metrics"): 1142 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1143 metrics = [ 1144 { 1145 int(metrics_hash): ( 1146 data["invisible"], 1147 self.deserialize_objectives(data["objectiveProgress"]) 1148 if "objectiveProgress" in data 1149 else None, 1150 ) 1151 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1152 } 1153 ] 1154 transitory: typing.Optional[fireteams.FireteamParty] = None 1155 if raw_transitory := payload.get("profileTransitoryData"): 1156 if "data" in raw_transitory: 1157 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1158 1159 item_components: typing.Optional[components.ItemsComponent] = None 1160 if raw_item_components := payload.get("itemComponents"): 1161 item_components = self.deserialize_items_component(raw_item_components) 1162 1163 profile_plugsets: typing.Optional[ 1164 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1165 ] = None 1166 1167 if raw_profile_plugs := payload.get("profilePlugSets"): 1168 profile_plugsets = { 1169 int(index): [self.deserialize_plug_item_state(state) for state in data] 1170 for index, data in raw_profile_plugs["data"]["plugs"].items() 1171 } 1172 1173 character_plugsets: typing.Optional[ 1174 collections.Mapping[ 1175 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1176 ] 1177 ] = None 1178 if raw_char_plugsets := payload.get("characterPlugSets"): 1179 character_plugsets = { 1180 int(char_id): { 1181 int(index): [ 1182 self.deserialize_plug_item_state(state) for state in data 1183 ] 1184 for index, data in inner["plugs"].items() 1185 } 1186 for char_id, inner in raw_char_plugsets["data"].items() 1187 } 1188 1189 character_collectibles: typing.Optional[ 1190 collections.Mapping[int, items.Collectible] 1191 ] = None 1192 if raw_character_collectibles := payload.get("characterCollectibles"): 1193 character_collectibles = { 1194 int(char_id): self._deserialize_collectible(data) 1195 for char_id, data in raw_character_collectibles["data"].items() 1196 } 1197 1198 profile_collectibles: typing.Optional[items.Collectible] = None 1199 if raw_profile_collectibles := payload.get("profileCollectibles"): 1200 profile_collectibles = self._deserialize_collectible( 1201 raw_profile_collectibles["data"] 1202 ) 1203 1204 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1205 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1206 profile_nodes = { 1207 int(node_hash): self._deserialize_node(node) 1208 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1209 } 1210 1211 character_nodes: typing.Optional[ 1212 collections.Mapping[int, collections.Mapping[int, records.Node]] 1213 ] = None 1214 if raw_character_nodes := payload.get("characterPresentationNodes"): 1215 character_nodes = { 1216 int(char_id): { 1217 int(node_hash): self._deserialize_node(node) 1218 for node_hash, node in each_character["nodes"].items() 1219 } 1220 for char_id, each_character in raw_character_nodes["data"].items() 1221 } 1222 1223 platform_silver: typing.Optional[ 1224 collections.Mapping[str, profile.ProfileItemImpl] 1225 ] = None 1226 if raw_platform_silver := payload.get("platformSilver"): 1227 if "data" in raw_platform_silver: 1228 platform_silver = { 1229 platform_name: self.deserialize_profile_item(item) 1230 for platform_name, item in raw_platform_silver["data"][ 1231 "platformSilver" 1232 ].items() 1233 } 1234 1235 character_currency_lookups: typing.Optional[ 1236 collections.Mapping[int, collections.Sequence[items.Currency]] 1237 ] = None 1238 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1239 if "data" in raw_char_lookups: 1240 character_currency_lookups = { 1241 int(char_id): self._deserialize_currencies(currencie) 1242 for char_id, currencie in raw_char_lookups["data"].items() 1243 } 1244 1245 character_craftables: typing.Optional[ 1246 collections.Mapping[int, components.CraftablesComponent] 1247 ] = None 1248 if raw_character_craftables := payload.get("characterCraftables"): 1249 1250 if "data" in raw_character_craftables: 1251 character_craftables = { 1252 int(char_id): self.deserialize_craftables_component(craftable) 1253 for char_id, craftable in raw_character_craftables["data"].items() 1254 } 1255 1256 return components.Component( 1257 profiles=profile_, 1258 profile_progression=profile_progression, 1259 profile_currencies=profile_currencies, 1260 profile_inventories=profile_inventories, 1261 profile_records=profile_records, 1262 characters=characters, 1263 character_records=character_records, 1264 character_equipments=character_equipments, 1265 character_inventories=character_inventories, 1266 character_activities=character_activities, 1267 character_render_data=character_render_data, 1268 character_progressions=character_progressions, 1269 profile_string_variables=profile_string_vars, 1270 character_string_variables=character_string_vars, 1271 metrics=metrics, 1272 root_node_hash=root_node_hash, 1273 transitory=transitory, 1274 item_components=item_components, 1275 profile_plugsets=profile_plugsets, 1276 character_plugsets=character_plugsets, 1277 character_collectibles=character_collectibles, 1278 profile_collectibles=profile_collectibles, 1279 profile_nodes=profile_nodes, 1280 character_nodes=character_nodes, 1281 platform_silver=platform_silver, 1282 character_currency_lookups=character_currency_lookups, 1283 character_craftables=character_craftables, 1284 ) 1285 1286 def deserialize_items_component( 1287 self, payload: typedefs.JSONObject 1288 ) -> components.ItemsComponent: 1289 instances: typing.Optional[ 1290 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1291 ] = None 1292 if raw_instances := payload.get("instances"): 1293 instances = [ 1294 { 1295 int(ins_id): self.deserialize_instanced_item(item) 1296 for ins_id, item in raw_instances["data"].items() 1297 } 1298 ] 1299 1300 render_data: typing.Optional[ 1301 collections.Mapping[int, tuple[bool, dict[int, int]]] 1302 ] = None 1303 if raw_render_data := payload.get("renderData"): 1304 render_data = { 1305 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1306 for ins_id, data in raw_render_data["data"].items() 1307 } 1308 1309 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1310 if raw_stats := payload.get("stats"): 1311 builder: collections.Mapping[int, items.ItemStatsView] = {} 1312 for ins_id, stat in raw_stats["data"].items(): 1313 for _, items_ in stat.items(): 1314 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1315 stats = builder 1316 1317 sockets: typing.Optional[ 1318 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1319 ] = None 1320 if raw_sockets := payload.get("sockets"): 1321 sockets = { 1322 int(ins_id): [ 1323 self.deserialize_item_socket(socket) for socket in item["sockets"] 1324 ] 1325 for ins_id, item in raw_sockets["data"].items() 1326 } 1327 1328 objeectives: typing.Optional[ 1329 collections.Mapping[int, collections.Sequence[records.Objective]] 1330 ] = None 1331 if raw_objectives := payload.get("objectives"): 1332 objeectives = { 1333 int(ins_id): [self.deserialize_objectives(objective)] 1334 for ins_id, data in raw_objectives["data"].items() 1335 for objective in data["objectives"] 1336 } 1337 1338 perks: typing.Optional[ 1339 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1340 ] = None 1341 if raw_perks := payload.get("perks"): 1342 perks = { 1343 int(ins_id): [ 1344 self.deserialize_item_perk(perk) for perk in item["perks"] 1345 ] 1346 for ins_id, item in raw_perks["data"].items() 1347 } 1348 1349 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1350 if raw_plug_states := payload.get("plugStates"): 1351 pending_states: list[items.PlugItemState] = [] 1352 for _, plug in raw_plug_states["data"].items(): 1353 pending_states.append(self.deserialize_plug_item_state(plug)) 1354 plug_states = pending_states 1355 1356 reusable_plugs: typing.Optional[ 1357 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1358 ] = None 1359 if raw_re_plugs := payload.get("reusablePlugs"): 1360 reusable_plugs = { 1361 int(ins_id): [ 1362 self.deserialize_plug_item_state(state) for state in inner 1363 ] 1364 for ins_id, plug in raw_re_plugs["data"].items() 1365 for inner in list(plug["plugs"].values()) 1366 } 1367 1368 plug_objectives: typing.Optional[ 1369 collections.Mapping[ 1370 int, collections.Mapping[int, collections.Collection[records.Objective]] 1371 ] 1372 ] = None 1373 if raw_plug_objectives := payload.get("plugObjectives"): 1374 plug_objectives = { 1375 int(ins_id): { 1376 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1377 for obj_hash, objs in inner["objectivesPerPlug"].items() 1378 } 1379 for ins_id, inner in raw_plug_objectives["data"].items() 1380 } 1381 1382 return components.ItemsComponent( 1383 sockets=sockets, 1384 stats=stats, 1385 render_data=render_data, 1386 instances=instances, 1387 objectives=objeectives, 1388 perks=perks, 1389 plug_states=plug_states, 1390 reusable_plugs=reusable_plugs, 1391 plug_objectives=plug_objectives, 1392 ) 1393 1394 def deserialize_character_component( # type: ignore[call-arg] 1395 self, payload: typedefs.JSONObject 1396 ) -> components.CharacterComponent: 1397 1398 character_: typing.Optional[character.Character] = None 1399 if raw_singuler_character := payload.get("character"): 1400 character_ = self.deserialize_character(raw_singuler_character["data"]) 1401 1402 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1403 if raw_inventory := payload.get("inventory"): 1404 if "data" in raw_inventory: 1405 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1406 1407 activities: typing.Optional[activity.CharacterActivity] = None 1408 if raw_activities := payload.get("activities"): 1409 activities = self.deserialize_character_activity(raw_activities["data"]) 1410 1411 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1412 if raw_equipments := payload.get("equipment"): 1413 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1414 1415 progressions_: typing.Optional[character.CharacterProgression] = None 1416 if raw_progressions := payload.get("progressions"): 1417 progressions_ = self.deserialize_character_progressions( 1418 raw_progressions["data"] 1419 ) 1420 1421 render_data: typing.Optional[character.RenderedData] = None 1422 if raw_render_data := payload.get("renderData"): 1423 render_data = self.deserialize_character_render_data( 1424 raw_render_data["data"] 1425 ) 1426 1427 character_records: typing.Optional[ 1428 collections.Mapping[int, records.CharacterRecord] 1429 ] = None 1430 if raw_char_records := payload.get("records"): 1431 character_records = self.deserialize_characters_records( 1432 raw_char_records["data"] 1433 ) 1434 1435 item_components: typing.Optional[components.ItemsComponent] = None 1436 if raw_item_components := payload.get("itemComponents"): 1437 item_components = self.deserialize_items_component(raw_item_components) 1438 1439 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1440 if raw_nodes := payload.get("presentationNodes"): 1441 nodes = { 1442 int(node_hash): self._deserialize_node(node) 1443 for node_hash, node in raw_nodes["data"]["nodes"].items() 1444 } 1445 1446 collectibles: typing.Optional[items.Collectible] = None 1447 if raw_collectibles := payload.get("collectibles"): 1448 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1449 1450 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1451 if raw_currencies := payload.get("currencyLookups"): 1452 if "data" in raw_currencies: 1453 currency_lookups = self._deserialize_currencies(raw_currencies) 1454 1455 return components.CharacterComponent( 1456 activities=activities, 1457 equipment=equipment, 1458 inventory=inventory, 1459 progressions=progressions_, 1460 render_data=render_data, 1461 character=character_, 1462 character_records=character_records, 1463 profile_records=None, 1464 item_components=item_components, 1465 currency_lookups=currency_lookups, 1466 collectibles=collectibles, 1467 nodes=nodes, 1468 ) 1469 1470 def _set_entity_attrs( 1471 self, payload: typedefs.JSONObject, *, key: str = "displayProperties" 1472 ) -> entity.Entity: 1473 1474 name: undefined.UndefinedOr[str] = undefined.Undefined 1475 description: undefined.UndefinedOr[str] = undefined.Undefined 1476 1477 if properties := payload[key]: 1478 if (raw_name := properties["name"]) is not typedefs.Unknown: 1479 name = raw_name 1480 1481 if ( 1482 raw_description := properties["description"] 1483 ) and not typedefs.is_unknown(raw_description): 1484 description = raw_description 1485 1486 return entity.Entity( 1487 net=self._net, 1488 hash=payload["hash"], 1489 index=payload["index"], 1490 name=name, 1491 description=description, 1492 has_icon=properties["hasIcon"], 1493 icon=assets.Image(properties["icon"] if "icon" in properties else None), 1494 ) 1495 1496 def deserialize_inventory_results( 1497 self, payload: typedefs.JSONObject 1498 ) -> iterators.FlatIterator[entity.SearchableEntity]: 1499 suggested_words: list[str] = payload["suggestedWords"] 1500 1501 def _check_unknown(s: str) -> undefined.UndefinedOr[str]: 1502 return s if not typedefs.is_unknown(s) else undefined.Undefined 1503 1504 return iterators.FlatIterator( 1505 [ 1506 entity.SearchableEntity( 1507 net=self._net, 1508 hash=data["hash"], 1509 entity_type=data["entityType"], 1510 weight=data["weight"], 1511 suggested_words=suggested_words, 1512 name=data["displayProperties"]["name"], 1513 has_icon=data["displayProperties"]["hasIcon"], 1514 description=_check_unknown( 1515 data["displayProperties"]["description"] 1516 ), 1517 icon=assets.Image(data["displayProperties"]["icon"]), 1518 ) 1519 for data in payload["results"]["results"] 1520 ] 1521 ) 1522 1523 def _deserialize_inventory_item_objects( 1524 self, payload: typedefs.JSONObject 1525 ) -> entity.InventoryEntityObjects: 1526 return entity.InventoryEntityObjects( 1527 action=payload.get("action"), 1528 set_data=payload.get("setData"), 1529 stats=payload.get("stats"), 1530 equipping_block=payload.get("equippingBlock"), 1531 translation_block=payload.get("translationBlock"), 1532 preview=payload.get("preview"), 1533 quality=payload.get("quality"), 1534 value=payload.get("value"), 1535 source_data=payload.get("sourceData"), 1536 objectives=payload.get("objectives"), 1537 plug=payload.get("plug"), 1538 metrics=payload.get("metrics"), 1539 gearset=payload.get("gearset"), 1540 sack=payload.get("sack"), 1541 sockets=payload.get("sockets"), 1542 summary=payload.get("summary"), 1543 talent_gird=payload.get("talentGrid"), 1544 investments_stats=payload.get("investmentStats"), 1545 perks=payload.get("perks"), 1546 animations=payload.get("animations", []), 1547 links=payload.get("links", []), 1548 ) 1549 1550 def deserialize_inventory_entity( # noqa: C901 Too complex. 1551 self, payload: typedefs.JSONObject, / 1552 ) -> entity.InventoryEntity: 1553 1554 props = self._set_entity_attrs(payload) 1555 objects = self._deserialize_inventory_item_objects(payload) 1556 1557 collectible_hash: typing.Optional[int] = None 1558 if raw_collectible_hash := payload.get("collectibleHash"): 1559 collectible_hash = int(raw_collectible_hash) 1560 1561 secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1562 if raw_second_icon := payload.get("secondaryIcon"): 1563 secondary_icon = assets.Image(raw_second_icon) 1564 1565 secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1566 if raw_second_overlay := payload.get("secondaryOverlay"): 1567 secondary_overlay = assets.Image(raw_second_overlay) 1568 1569 secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1570 if raw_second_special := payload.get("secondarySpecial"): 1571 secondary_special = assets.Image(raw_second_special) 1572 1573 screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1574 if raw_screenshot := payload.get("screenshot"): 1575 screenshot = assets.Image(raw_screenshot) 1576 1577 watermark_icon: typing.Optional[assets.Image] = None 1578 if raw_watermark_icon := payload.get("iconWatermark"): 1579 watermark_icon = assets.Image(raw_watermark_icon) 1580 1581 watermark_shelved: typing.Optional[assets.Image] = None 1582 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1583 watermark_shelved = assets.Image(raw_watermark_shelved) 1584 1585 about: undefined.UndefinedOr[str] = undefined.Undefined 1586 if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown( 1587 raw_about 1588 ): 1589 about = raw_about 1590 1591 ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined 1592 if ( 1593 raw_ui_style := payload.get("uiItemDisplayStyle") 1594 ) and not typedefs.is_unknown(raw_ui_style): 1595 ui_item_style = raw_ui_style 1596 1597 tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined 1598 if ( 1599 raw_tier_and_name := payload.get("itemTypeAndTierDisplayName") 1600 ) and not typedefs.is_unknown(raw_tier_and_name): 1601 tier_and_name = raw_tier_and_name 1602 1603 type_name: undefined.UndefinedOr[str] = undefined.Undefined 1604 if ( 1605 raw_type_name := payload.get("itemTypeDisplayName") 1606 ) and not typedefs.is_unknown(raw_type_name): 1607 type_name = raw_type_name 1608 1609 display_source: undefined.UndefinedOr[str] = undefined.Undefined 1610 if ( 1611 raw_display_source := payload.get("displaySource") 1612 ) and not typedefs.is_unknown(raw_display_source): 1613 display_source = raw_display_source 1614 1615 lorehash: typing.Optional[int] = None 1616 if raw_lore_hash := payload.get("loreHash"): 1617 lorehash = int(raw_lore_hash) 1618 1619 summary_hash: typing.Optional[int] = None 1620 if raw_summary_hash := payload.get("summaryItemHash"): 1621 summary_hash = raw_summary_hash 1622 1623 breaker_type_hash: typing.Optional[int] = None 1624 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1625 breaker_type_hash = int(raw_breaker_type_hash) 1626 1627 damage_types: typing.Optional[collections.Sequence[int]] = None 1628 if raw_damage_types := payload.get("damageTypes"): 1629 damage_types = [int(type_) for type_ in raw_damage_types] 1630 1631 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1632 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1633 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1634 1635 default_damagetype_hash: typing.Optional[int] = None 1636 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1637 default_damagetype_hash = int(raw_defaultdmg_hash) 1638 1639 emblem_objective_hash: typing.Optional[int] = None 1640 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1641 emblem_objective_hash = int(raw_emblem_obj_hash) 1642 1643 tier_type: typing.Optional[enums.TierType] = None 1644 tier: typing.Optional[enums.ItemTier] = None 1645 bucket_hash: typing.Optional[int] = None 1646 recovery_hash: typing.Optional[int] = None 1647 tier_name: undefined.UndefinedOr[str] = undefined.Undefined 1648 isinstance_item: bool = False 1649 expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined 1650 expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined 1651 suppress_expiration: bool = False 1652 max_stack_size: typing.Optional[int] = None 1653 stack_label: undefined.UndefinedOr[str] = undefined.Undefined 1654 1655 if inventory := payload.get("inventory"): 1656 tier_type = enums.TierType(int(inventory["tierType"])) 1657 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1658 bucket_hash = int(inventory["bucketTypeHash"]) 1659 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1660 tier_name = inventory["tierTypeName"] 1661 isinstance_item = inventory["isInstanceItem"] 1662 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1663 max_stack_size = int(inventory["maxStackSize"]) 1664 1665 try: 1666 stack_label = inventory["stackUniqueLabel"] 1667 except KeyError: 1668 pass 1669 1670 return entity.InventoryEntity( 1671 net=self._net, 1672 collectible_hash=collectible_hash, 1673 name=props.name, 1674 about=about, 1675 emblem_objective_hash=emblem_objective_hash, 1676 suppress_expiration=suppress_expiration, 1677 max_stack_size=max_stack_size, 1678 stack_label=stack_label, 1679 tier=tier, 1680 tier_type=tier_type, 1681 tier_name=tier_name, 1682 bucket_hash=bucket_hash, 1683 recovery_bucket_hash=recovery_hash, 1684 isinstance_item=isinstance_item, 1685 expire_in_orbit_message=expire_in_orbit_message, 1686 expiration_tooltip=expire_tool_tip, 1687 lore_hash=lorehash, 1688 type_and_tier_name=tier_and_name, 1689 summary_hash=summary_hash, 1690 ui_display_style=ui_item_style, 1691 type_name=type_name, 1692 breaker_type_hash=breaker_type_hash, 1693 description=props.description, 1694 display_source=display_source, 1695 hash=props.hash, 1696 damage_types=damage_types, 1697 index=props.index, 1698 icon=props.icon, 1699 has_icon=props.has_icon, 1700 screenshot=screenshot, 1701 watermark_icon=watermark_icon, 1702 watermark_shelved=watermark_shelved, 1703 secondary_icon=secondary_icon, 1704 secondary_overlay=secondary_overlay, 1705 secondary_special=secondary_special, 1706 type=enums.ItemType(int(payload["itemType"])), 1707 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1708 trait_ids=[trait for trait in payload.get("traitIds", [])], 1709 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1710 item_class=enums.Class(int(payload["classType"])), 1711 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1712 breaker_type=int(payload["breakerType"]), 1713 default_damagetype=int(payload["defaultDamageType"]), 1714 default_damagetype_hash=default_damagetype_hash, 1715 damagetype_hashes=damagetype_hashes, 1716 tooltip_notifications=payload["tooltipNotifications"], 1717 not_transferable=payload["nonTransferrable"], 1718 allow_actions=payload["allowActions"], 1719 is_equippable=payload["equippable"], 1720 objects=objects, 1721 background_colors=payload.get("backgroundColor", {}), 1722 season_hash=payload.get("seasonHash"), 1723 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1724 ) 1725 1726 def deserialize_objective_entity( 1727 self, payload: typedefs.JSONObject, / 1728 ) -> entity.ObjectiveEntity: 1729 props = self._set_entity_attrs(payload) 1730 return entity.ObjectiveEntity( 1731 net=self._net, 1732 hash=props.hash, 1733 index=props.index, 1734 description=props.description, 1735 name=props.name, 1736 has_icon=props.has_icon, 1737 icon=props.icon, 1738 unlock_value_hash=payload["unlockValueHash"], 1739 completion_value=payload["completionValue"], 1740 scope=entity.GatingScope(int(payload["scope"])), 1741 location_hash=payload["locationHash"], 1742 allowed_negative_value=payload["allowNegativeValue"], 1743 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1744 counting_downward=payload["isCountingDownward"], 1745 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1746 progress_description=payload["progressDescription"], 1747 perks=payload["perks"], 1748 stats=payload["stats"], 1749 minimum_visibility=payload["minimumVisibilityThreshold"], 1750 allow_over_completion=payload["allowOvercompletion"], 1751 show_value_style=payload["showValueOnComplete"], 1752 display_only_objective=payload["isDisplayOnlyObjective"], 1753 complete_value_style=entity.ValueUIStyle( 1754 int(payload["completedValueStyle"]) 1755 ), 1756 progress_value_style=entity.ValueUIStyle( 1757 int(payload["inProgressValueStyle"]) 1758 ), 1759 ui_label=payload["uiLabel"], 1760 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1761 ) 1762 1763 def _deserialize_activity_values( 1764 self, payload: typedefs.JSONObject, / 1765 ) -> activity.ActivityValues: 1766 team: typing.Optional[int] = None 1767 if raw_team := payload.get("team"): 1768 team = raw_team["basic"]["value"] 1769 return activity.ActivityValues( 1770 assists=payload["assists"]["basic"]["value"], 1771 deaths=payload["deaths"]["basic"]["value"], 1772 kills=payload["kills"]["basic"]["value"], 1773 is_completed=bool(payload["completed"]["basic"]["value"]), 1774 opponents_defeated=payload["opponentsDefeated"]["basic"]["value"], 1775 efficiency=payload["efficiency"]["basic"]["value"], 1776 kd_ratio=payload["killsDeathsRatio"]["basic"]["value"], 1777 kd_assists=payload["killsDeathsAssists"]["basic"]["value"], 1778 score=payload["score"]["basic"]["value"], 1779 duration=payload["activityDurationSeconds"]["basic"]["displayValue"], 1780 team=team, 1781 completion_reason=payload["completionReason"]["basic"]["displayValue"], 1782 fireteam_id=payload["fireteamId"]["basic"]["value"], 1783 start_seconds=payload["startSeconds"]["basic"]["value"], 1784 played_time=payload["timePlayedSeconds"]["basic"]["displayValue"], 1785 player_count=payload["playerCount"]["basic"]["value"], 1786 team_score=payload["teamScore"]["basic"]["value"], 1787 ) 1788 1789 def deserialize_activity( 1790 self, 1791 payload: typedefs.JSONObject, 1792 /, 1793 ) -> activity.Activity: 1794 period = time.clean_date(payload["period"]) 1795 details = payload["activityDetails"] 1796 ref_id = int(details["referenceId"]) 1797 instance_id = int(details["instanceId"]) 1798 mode = enums.GameMode(details["mode"]) 1799 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1800 is_private = details["isPrivate"] 1801 membership_type = enums.MembershipType(int(details["membershipType"])) 1802 1803 # Since we're using the same fields for post activity method 1804 # this check is required since post activity doesn't values values 1805 values = self._deserialize_activity_values(payload["values"]) 1806 1807 return activity.Activity( 1808 net=self._net, 1809 hash=ref_id, 1810 instance_id=instance_id, 1811 mode=mode, 1812 modes=modes, 1813 is_private=is_private, 1814 membership_type=membership_type, 1815 occurred_at=period, 1816 values=values, 1817 ) 1818 1819 def deserialize_activities( 1820 self, payload: typedefs.JSONObject 1821 ) -> iterators.FlatIterator[activity.Activity]: 1822 return iterators.FlatIterator( 1823 [ 1824 self.deserialize_activity(activity_) 1825 for activity_ in payload["activities"] 1826 ] 1827 ) 1828 1829 def deserialize_extended_weapon_values( 1830 self, payload: typedefs.JSONObject 1831 ) -> activity.ExtendedWeaponValues: 1832 1833 assists: typing.Optional[int] = None 1834 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1835 assists = raw_assists["basic"]["value"] 1836 assists_damage: typing.Optional[int] = None 1837 1838 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1839 assists_damage = raw_assists_damage["basic"]["value"] 1840 1841 return activity.ExtendedWeaponValues( 1842 reference_id=int(payload["referenceId"]), 1843 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1844 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1845 "value" 1846 ], 1847 assists=assists, 1848 assists_damage=assists_damage, 1849 precision_kills_percentage=( 1850 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1851 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1852 "displayValue" 1853 ], 1854 ), 1855 ) 1856 1857 def _deserialize_extended_values( 1858 self, payload: typedefs.JSONObject 1859 ) -> activity.ExtendedValues: 1860 weapons: typing.Optional[ 1861 collections.Collection[activity.ExtendedWeaponValues] 1862 ] = None 1863 1864 if raw_weapons := payload.get("weapons"): 1865 weapons = [ 1866 self.deserialize_extended_weapon_values(value) for value in raw_weapons 1867 ] 1868 1869 return activity.ExtendedValues( 1870 precision_kills=payload["values"]["precisionKills"]["basic"]["value"], 1871 grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"], 1872 melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"], 1873 super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"], 1874 ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"], 1875 weapons=weapons, 1876 ) 1877 1878 def deserialize_post_activity_player( 1879 self, payload: typedefs.JSONObject, / 1880 ) -> activity.PostActivityPlayer: 1881 player = payload["player"] 1882 1883 class_hash: typedefs.NoneOr[int] = None 1884 if (class_hash := player.get("classHash")) is not None: 1885 class_hash = class_hash 1886 1887 race_hash: typedefs.NoneOr[int] = None 1888 if (race_hash := player.get("raceHash")) is not None: 1889 race_hash = race_hash 1890 1891 gender_hash: typedefs.NoneOr[int] = None 1892 if (gender_hash := player.get("genderHash")) is not None: 1893 gender_hash = gender_hash 1894 1895 character_class: undefined.UndefinedOr[str] = undefined.Undefined 1896 if ( 1897 character_class := player.get("characterClass") 1898 ) and not typedefs.is_unknown(character_class): 1899 character_class = character_class 1900 1901 character_level: typedefs.NoneOr[int] = None 1902 if (character_level := player.get("characterLevel")) is not None: 1903 character_level = character_level 1904 1905 return activity.PostActivityPlayer( 1906 standing=int(payload["standing"]), 1907 score=int(payload["score"]["basic"]["value"]), 1908 character_id=payload["characterId"], 1909 destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]), 1910 character_class=character_class, 1911 character_level=character_level, 1912 race_hash=race_hash, 1913 gender_hash=gender_hash, 1914 class_hash=class_hash, 1915 light_level=int(player["lightLevel"]), 1916 emblem_hash=int(player["emblemHash"]), 1917 values=self._deserialize_activity_values(payload["values"]), 1918 extended_values=self._deserialize_extended_values(payload["extended"]), 1919 ) 1920 1921 def _deserialize_post_activity_team( 1922 self, payload: typedefs.JSONObject 1923 ) -> activity.PostActivityTeam: 1924 return activity.PostActivityTeam( 1925 id=payload["teamId"], 1926 is_defeated=bool(payload["standing"]["basic"]["value"]), 1927 score=int(payload["score"]["basic"]["value"]), 1928 name=payload["teamName"], 1929 ) 1930 1931 def deserialize_post_activity( 1932 self, payload: typedefs.JSONObject 1933 ) -> activity.PostActivity: 1934 period = time.clean_date(payload["period"]) 1935 details = payload["activityDetails"] 1936 ref_id = int(details["referenceId"]) 1937 instance_id = int(details["instanceId"]) 1938 mode = enums.GameMode(details["mode"]) 1939 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1940 is_private = details["isPrivate"] 1941 membership_type = enums.MembershipType(int(details["membershipType"])) 1942 return activity.PostActivity( 1943 net=self._net, 1944 hash=ref_id, 1945 membership_type=membership_type, 1946 instance_id=instance_id, 1947 mode=mode, 1948 modes=modes, 1949 is_private=is_private, 1950 occurred_at=period, 1951 starting_phase=int(payload["startingPhaseIndex"]), 1952 players=[ 1953 self.deserialize_post_activity_player(player) 1954 for player in payload["entries"] 1955 ], 1956 teams=[ 1957 self._deserialize_post_activity_team(team) for team in payload["teams"] 1958 ], 1959 ) 1960 1961 def _deserialize_aggregated_activity_values( 1962 self, payload: typedefs.JSONObject 1963 ) -> activity.AggregatedActivityValues: 1964 # This ID is always the same for all aggregated values. 1965 activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"]) 1966 1967 return activity.AggregatedActivityValues( 1968 id=activity_id, 1969 fastest_completion_time=( 1970 int(payload["fastestCompletionMsForActivity"]["basic"]["value"]), 1971 payload["fastestCompletionMsForActivity"]["basic"]["displayValue"], 1972 ), 1973 completions=int(payload["activityCompletions"]["basic"]["value"]), 1974 kills=int(payload["activityKills"]["basic"]["value"]), 1975 deaths=int(payload["activityDeaths"]["basic"]["value"]), 1976 assists=int(payload["activityAssists"]["basic"]["value"]), 1977 seconds_played=( 1978 int(payload["activitySecondsPlayed"]["basic"]["value"]), 1979 payload["activitySecondsPlayed"]["basic"]["displayValue"], 1980 ), 1981 wins=int(payload["activityWins"]["basic"]["value"]), 1982 goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]), 1983 special_actions=int(payload["activitySpecialActions"]["basic"]["value"]), 1984 best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]), 1985 best_single_score=int( 1986 payload["activityBestSingleGameScore"]["basic"]["value"] 1987 ), 1988 goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]), 1989 special_score=int(payload["activitySpecialScore"]["basic"]["value"]), 1990 kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]), 1991 kd_ratio=float( 1992 payload["activityKillsDeathsAssists"]["basic"]["displayValue"] 1993 ), 1994 precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]), 1995 ) 1996 1997 def deserialize_aggregated_activity( 1998 self, payload: typedefs.JSONObject 1999 ) -> activity.AggregatedActivity: 2000 return activity.AggregatedActivity( 2001 hash=int(payload["activityHash"]), 2002 values=self._deserialize_aggregated_activity_values(payload["values"]), 2003 ) 2004 2005 def deserialize_aggregated_activities( 2006 self, payload: typedefs.JSONObject 2007 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 2008 return iterators.FlatIterator( 2009 [ 2010 self.deserialize_aggregated_activity(activity) 2011 for activity in payload["activities"] 2012 ] 2013 ) 2014 2015 def deserialize_linked_profiles( 2016 self, payload: typedefs.JSONObject 2017 ) -> profile.LinkedProfile: 2018 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 2019 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2020 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2021 2022 if raw_profile := payload.get("profiles"): 2023 for pfile in raw_profile: 2024 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 2025 2026 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 2027 for raw_error_pfile in raw_profiles_with_errors: 2028 if error_pfile := raw_error_pfile.get("infoCard"): 2029 error_profiles_vec.append( 2030 self.deserialize_destiny_membership(error_pfile) 2031 ) 2032 2033 return profile.LinkedProfile( 2034 net=self._net, 2035 bungie=bungie_user, 2036 profiles=profiles_vec, 2037 profiles_with_errors=error_profiles_vec, 2038 ) 2039 2040 def deserialize_clan_banners( 2041 self, payload: typedefs.JSONObject 2042 ) -> collections.Sequence[clans.ClanBanner]: 2043 banners_seq: typing.MutableSequence[clans.ClanBanner] = [] 2044 if banners := payload.get("clanBannerDecals"): 2045 for k, v in banners.items(): 2046 banner_obj = clans.ClanBanner( 2047 id=int(k), 2048 foreground=assets.Image(v["foregroundPath"]), 2049 background=assets.Image(v["backgroundPath"]), 2050 ) 2051 banners_seq.append(banner_obj) 2052 return banners_seq 2053 2054 def deserialize_public_milestone_content( 2055 self, payload: typedefs.JSONObject 2056 ) -> milestones.MilestoneContent: 2057 items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None 2058 if raw_categories := payload.get("itemCategories"): 2059 for item in raw_categories: 2060 title = undefined.Undefined 2061 if raw_title := item.get("title"): 2062 if raw_title != typedefs.Unknown: 2063 title = raw_title 2064 if raw_hashes := item.get("itemHashes"): 2065 hashes: collections.Sequence[int] = raw_hashes 2066 2067 items_categoris = milestones.MilestoneItems(title=title, hashes=hashes) 2068 2069 about = undefined.Undefined 2070 if (raw_about := payload["about"]) != typedefs.Unknown: 2071 about = raw_about 2072 2073 status = undefined.Undefined 2074 if (raw_status := payload["status"]) != typedefs.Unknown: 2075 status = raw_status 2076 2077 tips: typing.MutableSequence[undefined.UndefinedOr[str]] = [] 2078 if raw_tips := payload.get("tips"): 2079 for raw_tip in raw_tips: 2080 if raw_tip == typedefs.Unknown: 2081 raw_tip = undefined.Undefined 2082 tips.append(raw_tip) 2083 2084 return milestones.MilestoneContent( 2085 about=about, status=status, tips=tips, items=items_categoris 2086 ) 2087 2088 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2089 name = undefined.Undefined 2090 if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown: 2091 name = raw_name 2092 2093 bungie_user: typedefs.NoneOr[user.BungieUser] = None 2094 2095 if raw_bungie_user := payload.get("bungieNetUser"): 2096 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2097 2098 return friends.Friend( 2099 net=self._net, 2100 id=int(payload["lastSeenAsMembershipId"]), 2101 name=name, 2102 code=payload.get("bungieGlobalDisplayNameCode"), 2103 relationship=enums.Relationship(payload["relationship"]), 2104 user=bungie_user, 2105 online_status=enums.Presence(payload["onlineStatus"]), 2106 online_title=payload["onlineTitle"], 2107 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2108 ) 2109 2110 def deserialize_friends( 2111 self, payload: typedefs.JSONObject 2112 ) -> collections.Sequence[friends.Friend]: 2113 mut_seq: typing.MutableSequence[friends.Friend] = [] 2114 if raw_friends := payload.get("friends"): 2115 for friend in raw_friends: 2116 mut_seq.append(self.deserialize_friend(friend)) 2117 return mut_seq 2118 2119 def deserialize_friend_requests( 2120 self, payload: typedefs.JSONObject 2121 ) -> friends.FriendRequestView: 2122 incoming: typing.MutableSequence[friends.Friend] = [] 2123 outgoing: typing.MutableSequence[friends.Friend] = [] 2124 2125 if raw_incoming_requests := payload.get("incomingRequests"): 2126 for incoming_request in raw_incoming_requests: 2127 incoming.append(self.deserialize_friend(incoming_request)) 2128 2129 if raw_outgoing_requests := payload.get("outgoingRequests"): 2130 for outgoing_request in raw_outgoing_requests: 2131 outgoing.append(self.deserialize_friend(outgoing_request)) 2132 2133 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing) 2134 2135 def _set_fireteam_fields( 2136 self, payload: typedefs.JSONObject, total_results: typing.Optional[int] = None 2137 ) -> fireteams.Fireteam: 2138 activity_type = fireteams.FireteamActivity(payload["activityType"]) 2139 return fireteams.Fireteam( 2140 id=int(payload["fireteamId"]), 2141 group_id=int(payload["groupId"]), 2142 platform=fireteams.FireteamPlatform(payload["platform"]), 2143 is_immediate=payload["isImmediate"], 2144 activity_type=activity_type, 2145 owner_id=int(payload["ownerMembershipId"]), 2146 player_slot_count=payload["playerSlotCount"], 2147 available_player_slots=payload["availablePlayerSlotCount"], 2148 available_alternate_slots=payload["availableAlternateSlotCount"], 2149 title=payload["title"], 2150 date_created=time.clean_date(payload["dateCreated"]), 2151 is_public=payload["isPublic"], 2152 locale=fireteams.FireteamLanguage(payload["locale"]), 2153 is_valid=payload["isValid"], 2154 last_modified=time.clean_date(payload["datePlayerModified"]), 2155 total_results=total_results or 0, 2156 ) 2157 2158 def deserialize_fireteams( 2159 self, payload: typedefs.JSONObject 2160 ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]: 2161 fireteams_: typing.MutableSequence[fireteams.Fireteam] = [] 2162 2163 result: list[typedefs.JSONObject] 2164 if not (result := payload["results"]): 2165 return None 2166 for elem in result: 2167 fireteams_.append( 2168 self._set_fireteam_fields( 2169 elem, total_results=int(payload["totalResults"]) 2170 ) 2171 ) 2172 return fireteams_ 2173 2174 def deserialize_fireteam_destiny_users( 2175 self, payload: typedefs.JSONObject 2176 ) -> fireteams.FireteamUser: 2177 destiny_obj = self.deserialize_destiny_membership(payload) 2178 # We could helpers.just return a DestinyMembership object but this is 2179 # missing the fireteam display name and id fields. 2180 return fireteams.FireteamUser( 2181 net=self._net, 2182 id=destiny_obj.id, 2183 code=destiny_obj.code, 2184 icon=destiny_obj.icon, 2185 types=destiny_obj.types, 2186 type=destiny_obj.type, 2187 is_public=destiny_obj.is_public, 2188 crossave_override=destiny_obj.crossave_override, 2189 name=destiny_obj.name, 2190 last_seen_name=destiny_obj.last_seen_name, 2191 fireteam_display_name=payload["FireteamDisplayName"], 2192 fireteam_membership_id=enums.MembershipType( 2193 payload["FireteamMembershipType"] 2194 ), 2195 ) 2196 2197 def deserialize_fireteam_members( 2198 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2199 ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]: 2200 members_: list[fireteams.FireteamMember] = [] 2201 if members := payload.get("Members" if not alternatives else "Alternates"): 2202 for member in members: 2203 bungie_fields = self.deserialize_partial_bungie_user(member) 2204 members_fields = fireteams.FireteamMember( 2205 destiny_user=self.deserialize_fireteam_destiny_users(member), 2206 has_microphone=member["hasMicrophone"], 2207 character_id=int(member["characterId"]), 2208 date_joined=time.clean_date(member["dateJoined"]), 2209 last_platform_invite_date=time.clean_date( 2210 member["lastPlatformInviteAttemptDate"] 2211 ), 2212 last_platform_invite_result=int( 2213 member["lastPlatformInviteAttemptResult"] 2214 ), 2215 net=self._net, 2216 name=bungie_fields.name, 2217 id=bungie_fields.id, 2218 icon=bungie_fields.icon, 2219 is_public=bungie_fields.is_public, 2220 crossave_override=bungie_fields.crossave_override, 2221 types=bungie_fields.types, 2222 type=bungie_fields.type, 2223 ) 2224 members_.append(members_fields) 2225 else: 2226 return None 2227 return members_ 2228 2229 def deserialize_available_fireteams( 2230 self, 2231 data: typedefs.JSONObject, 2232 *, 2233 no_results: bool = False, 2234 ) -> typing.Union[ 2235 fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam] 2236 ]: 2237 fireteams_: list[fireteams.AvailableFireteam] = [] 2238 2239 # This needs to be used outside the results 2240 # JSON key. 2241 if no_results is True: 2242 payload = data 2243 2244 if result := payload.get("results"): 2245 2246 for fireteam in result: 2247 found_fireteams = self._set_fireteam_fields(fireteam["Summary"]) 2248 fireteams_fields = fireteams.AvailableFireteam( 2249 id=found_fireteams.id, 2250 group_id=found_fireteams.group_id, 2251 platform=found_fireteams.platform, 2252 activity_type=found_fireteams.activity_type, 2253 is_immediate=found_fireteams.is_immediate, 2254 is_public=found_fireteams.is_public, 2255 is_valid=found_fireteams.is_valid, 2256 owner_id=found_fireteams.owner_id, 2257 player_slot_count=found_fireteams.player_slot_count, 2258 available_player_slots=found_fireteams.available_player_slots, 2259 available_alternate_slots=found_fireteams.available_alternate_slots, 2260 title=found_fireteams.title, 2261 date_created=found_fireteams.date_created, 2262 locale=found_fireteams.locale, 2263 last_modified=found_fireteams.last_modified, 2264 total_results=found_fireteams.total_results, 2265 members=self.deserialize_fireteam_members(payload), 2266 alternatives=self.deserialize_fireteam_members( 2267 payload, alternatives=True 2268 ), 2269 ) 2270 fireteams_.append(fireteams_fields) 2271 if no_results: 2272 return fireteams_fields 2273 return fireteams_ 2274 2275 def deserialize_fireteam_party( 2276 self, payload: typedefs.JSONObject 2277 ) -> fireteams.FireteamParty: 2278 last_destination_hash: typing.Optional[int] = None 2279 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2280 last_destination_hash = int(raw_dest_hash) 2281 2282 return fireteams.FireteamParty( 2283 members=[ 2284 self._deserialize_fireteam_party_member(member) 2285 for member in payload["partyMembers"] 2286 ], 2287 activity=self._deserialize_fireteam_party_current_activity( 2288 payload["currentActivity"] 2289 ), 2290 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2291 last_destination_hash=last_destination_hash, 2292 tracking=payload["tracking"], 2293 ) 2294 2295 def _deserialize_fireteam_party_member( 2296 self, payload: typedefs.JSONObject 2297 ) -> fireteams.FireteamPartyMember: 2298 2299 status = fireteams.FireteamPartyMemberState(payload["status"]) 2300 displayname: undefined.UndefinedOr[str] = undefined.Undefined 2301 if raw_name := payload.get("displayName"): 2302 displayname = raw_name 2303 2304 return fireteams.FireteamPartyMember( 2305 membership_id=int(payload["membershipId"]), 2306 emblem_hash=int(payload["emblemHash"]), 2307 status=status, 2308 display_name=displayname, 2309 ) 2310 2311 def _deserialize_fireteam_party_current_activity( 2312 self, payload: typedefs.JSONObject 2313 ) -> fireteams.FireteamPartyCurrentActivity: 2314 start_date: typing.Optional[datetime.datetime] = None 2315 if raw_start_date := payload.get("startTime"): 2316 start_date = time.clean_date(raw_start_date) 2317 2318 end_date: typing.Optional[datetime.datetime] = None 2319 if raw_end_date := payload.get("endTime"): 2320 end_date = time.clean_date(raw_end_date) 2321 return fireteams.FireteamPartyCurrentActivity( 2322 start_time=start_date, 2323 end_time=end_date, 2324 score=float(payload["score"]), 2325 highest_opposing_score=float(payload["highestOpposingFactionScore"]), 2326 opponenst_count=int(payload["numberOfOpponents"]), 2327 player_count=int(payload["numberOfPlayers"]), 2328 ) 2329 2330 def _deserialize_fireteam_party_settings( 2331 self, payload: typedefs.JSONObject 2332 ) -> fireteams.FireteamPartySettings: 2333 closed_reasons = enums.ClosedReasons(payload["closedReasons"]) 2334 return fireteams.FireteamPartySettings( 2335 open_slots=int(payload["openSlots"]), 2336 privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])), 2337 closed_reasons=closed_reasons, 2338 ) 2339 2340 def deserialize_seasonal_artifact( 2341 self, payload: typedefs.JSONObject 2342 ) -> season.Artifact: 2343 if raw_artifact := payload.get("seasonalArtifact"): 2344 if points := raw_artifact.get("pointProgression"): 2345 points_prog = progressions.Progression( 2346 hash=points["progressionHash"], 2347 level=points["level"], 2348 cap=points["levelCap"], 2349 daily_limit=points["dailyLimit"], 2350 weekly_limit=points["weeklyLimit"], 2351 current_progress=points["currentProgress"], 2352 daily_progress=points["dailyProgress"], 2353 needed=points["progressToNextLevel"], 2354 next_level=points["nextLevelAt"], 2355 ) 2356 2357 if bonus := raw_artifact.get("powerBonusProgression"): 2358 power_bonus_prog = progressions.Progression( 2359 hash=bonus["progressionHash"], 2360 level=bonus["level"], 2361 cap=bonus["levelCap"], 2362 daily_limit=bonus["dailyLimit"], 2363 weekly_limit=bonus["weeklyLimit"], 2364 current_progress=bonus["currentProgress"], 2365 daily_progress=bonus["dailyProgress"], 2366 needed=bonus["progressToNextLevel"], 2367 next_level=bonus["nextLevelAt"], 2368 ) 2369 artifact = season.Artifact( 2370 net=self._net, 2371 hash=raw_artifact["artifactHash"], 2372 power_bonus=raw_artifact["powerBonus"], 2373 acquired_points=raw_artifact["pointsAcquired"], 2374 bonus=power_bonus_prog, 2375 points=points_prog, 2376 ) 2377 return artifact 2378 2379 def deserialize_profile_progression( 2380 self, payload: typedefs.JSONObject 2381 ) -> profile.ProfileProgression: 2382 return profile.ProfileProgression( 2383 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2384 checklist={ 2385 int(check_id): checklists 2386 for check_id, checklists in payload["data"]["checklists"].items() 2387 }, 2388 ) 2389 2390 def deserialize_instanced_item( 2391 self, payload: typedefs.JSONObject 2392 ) -> items.ItemInstance: 2393 damage_type_hash: typing.Optional[int] = None 2394 if raw_damagetype_hash := payload.get("damageTypeHash"): 2395 damage_type_hash = int(raw_damagetype_hash) 2396 2397 required_hashes: typing.Optional[collections.Collection[int]] = None 2398 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2399 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2400 2401 breaker_type: typing.Optional[items.ItemBreakerType] = None 2402 if raw_break_type := payload.get("breakerType"): 2403 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2404 2405 breaker_type_hash: typing.Optional[int] = None 2406 if raw_break_type_hash := payload.get("breakerTypeHash"): 2407 breaker_type_hash = int(raw_break_type_hash) 2408 2409 energy: typing.Optional[items.ItemEnergy] = None 2410 if raw_energy := payload.get("energy"): 2411 energy = self.deserialize_item_energy(raw_energy) 2412 2413 primary_stats = None 2414 if raw_primary_stats := payload.get("primaryStat"): 2415 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2416 2417 return items.ItemInstance( 2418 damage_type=enums.DamageType(int(payload["damageType"])), 2419 damage_type_hash=damage_type_hash, 2420 primary_stat=primary_stats, 2421 item_level=int(payload["itemLevel"]), 2422 quality=int(payload["quality"]), 2423 is_equipped=payload["isEquipped"], 2424 can_equip=payload["canEquip"], 2425 equip_required_level=int(payload["equipRequiredLevel"]), 2426 required_equip_unlock_hashes=required_hashes, 2427 cant_equip_reason=int(payload["cannotEquipReason"]), 2428 breaker_type=breaker_type, 2429 breaker_type_hash=breaker_type_hash, 2430 energy=energy, 2431 ) 2432 2433 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2434 energy_hash: typing.Optional[int] = None 2435 if raw_energy_hash := payload.get("energyTypeHash"): 2436 energy_hash = int(raw_energy_hash) 2437 2438 return items.ItemEnergy( 2439 hash=energy_hash, 2440 type=items.ItemEnergyType(int(payload["energyType"])), 2441 capacity=int(payload["energyCapacity"]), 2442 used_energy=int(payload["energyUsed"]), 2443 unused_energy=int(payload["energyUnused"]), 2444 ) 2445 2446 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2447 perk_hash: typing.Optional[int] = None 2448 if raw_perk_hash := payload.get("perkHash"): 2449 perk_hash = int(raw_perk_hash) 2450 2451 return items.ItemPerk( 2452 hash=perk_hash, 2453 icon=assets.Image(payload["iconPath"]), 2454 is_active=payload["isActive"], 2455 is_visible=payload["visible"], 2456 ) 2457 2458 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2459 plug_hash: typing.Optional[int] = None 2460 if raw_plug_hash := payload.get("plugHash"): 2461 plug_hash = int(raw_plug_hash) 2462 2463 enable_fail_indexes: typing.Optional[list[int]] = None 2464 if raw_indexes := payload.get("enableFailIndexes"): 2465 enable_fail_indexes = [int(index) for index in raw_indexes] 2466 2467 return items.ItemSocket( 2468 plug_hash=plug_hash, 2469 is_enabled=payload["isEnabled"], 2470 enable_fail_indexes=enable_fail_indexes, 2471 is_visible=payload.get("visible"), 2472 ) 2473 2474 def deserialize_item_stats_view( 2475 self, payload: typedefs.JSONObject 2476 ) -> items.ItemStatsView: 2477 return items.ItemStatsView( 2478 stat_hash=payload.get("statHash"), value=payload.get("value") 2479 ) 2480 2481 def deserialize_plug_item_state( 2482 self, payload: typedefs.JSONObject 2483 ) -> items.PlugItemState: 2484 item_hash: typing.Optional[int] = None 2485 if raw_item_hash := payload.get("plugItemHash"): 2486 item_hash = int(raw_item_hash) 2487 2488 insert_fail_indexes: typedefs.NoneOr[list[int]] = None 2489 if raw_fail_indexes := payload.get("insertFailIndexes"): 2490 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2491 2492 enable_fail_indexes: typedefs.NoneOr[list[int]] = None 2493 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2494 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2495 2496 return items.PlugItemState( 2497 item_hash=item_hash, 2498 insert_fail_indexes=insert_fail_indexes, 2499 enable_fail_indexes=enable_fail_indexes, 2500 is_enabled=payload["enabled"], 2501 can_insert=payload["canInsert"], 2502 )
The base deserialization factory class for all aiobungie objects.
Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them
into a aiobungie.crates Python classes.
73 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 74 return user.BungieUser( 75 id=int(data["membershipId"]), 76 created_at=time.clean_date(data["firstAccess"]), 77 name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined), 78 is_deleted=data["isDeleted"], 79 about=data["about"], 80 updated_at=time.clean_date(data["lastUpdate"]), 81 psn_name=data.get("psnDisplayName", None), 82 stadia_name=data.get("stadiaDisplayName", None), 83 steam_name=data.get("steamDisplayName", None), 84 twitch_name=data.get("twitchDisplayName", None), 85 blizzard_name=data.get("blizzardDisplayName", None), 86 status=data["statusText"], 87 locale=data["locale"], 88 picture=assets.Image(path=str(data["profilePicturePath"])), 89 code=data.get("cachedBungieGlobalDisplayNameCode", None), 90 unique_name=data.get("uniqueName", None), 91 theme_id=int(data["profileTheme"]), 92 show_activity=bool(data["showActivity"]), 93 theme_name=data["profileThemeName"], 94 display_title=data["userTitleDisplay"], 95 )
Deserialize a raw JSON Bungie.net user only payload into a user object.
This only returns the Bungie.net user and not the Destiny memberships.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.BungieUser: A Bungie user.
97 def deserialize_partial_bungie_user( 98 self, payload: typedefs.JSONObject 99 ) -> user.PartialBungieUser: 100 return user.PartialBungieUser( 101 net=self._net, 102 types=[ 103 enums.MembershipType(type_) 104 for type_ in payload.get("applicableMembershipTypes", []) 105 ], 106 name=payload.get("displayName", undefined.Undefined), 107 id=int(payload["membershipId"]), 108 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 109 is_public=payload["isPublic"], 110 icon=assets.Image(payload.get("iconPath", "")), 111 type=enums.MembershipType(payload["membershipType"]), 112 )
Deserialize a raw JSON of a partial bungieNetUserInfo.
A partial user is a bungie.net user payload with missing information from
the main BungieUser object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PartialBungieUser: A partial bungie user.
114 def deserialize_destiny_membership( 115 self, payload: typedefs.JSONObject 116 ) -> user.DestinyMembership: 117 name: undefined.UndefinedOr[str] = undefined.Undefined 118 if ( 119 raw_name := payload.get("bungieGlobalDisplayName", "") 120 ) and not typedefs.is_unknown(raw_name): 121 name = raw_name 122 123 return user.DestinyMembership( 124 net=self._net, 125 id=int(payload["membershipId"]), 126 name=name, 127 code=payload.get("bungieGlobalDisplayNameCode", None), 128 last_seen_name=payload.get("LastSeenDisplayName") 129 or payload.get("displayName") # noqa: W503 130 or "", # noqa: W503 131 type=enums.MembershipType(payload["membershipType"]), 132 is_public=payload["isPublic"], 133 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 134 icon=assets.Image(payload.get("iconPath", "")), 135 types=[ 136 enums.MembershipType(type_) 137 for type_ in payload.get("applicableMembershipTypes", []) 138 ], 139 )
Deserialize a raw JSON of destinyUserInfo destiny membership information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
141 def deserialize_destiny_memberships( 142 self, data: typedefs.JSONArray 143 ) -> collections.Sequence[user.DestinyMembership]: 144 return [self.deserialize_destiny_membership(membership) for membership in data]
Deserialize a raw JSON payload/array of destinyUserInfo.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
146 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 147 148 primary_membership_id: typing.Optional[int] = None 149 if raw_primary_id := data.get("primaryMembershipId"): 150 primary_membership_id = int(raw_primary_id) 151 152 return user.User( 153 bungie=self.deserialize_bungie_user(data["bungieNetUser"]), 154 destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]), 155 primary_membership_id=primary_membership_id, 156 )
Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.User: A user object.
158 def deserialize_searched_user( 159 self, payload: typedefs.JSONObject 160 ) -> user.SearchableDestinyUser: 161 name: undefined.UndefinedOr[str] = undefined.Undefined 162 if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown( 163 raw_name 164 ): 165 name = raw_name 166 167 code: typing.Optional[int] = None 168 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 169 code = int(raw_code) 170 171 bungie_id: typing.Optional[int] = None 172 if raw_bungie_id := payload.get("bungieNetMembershipId"): 173 bungie_id = int(raw_bungie_id) 174 175 return user.SearchableDestinyUser( 176 name=name, 177 code=code, 178 bungie_id=bungie_id, 179 memberships=self.deserialize_destiny_memberships( 180 payload["destinyMemberships"] 181 ), 182 )
Deserialize the results of user search details.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.SearchableDestinyUser: The searched for Destiny 2 membership.
184 def deserialize_user_credentials( 185 self, payload: typedefs.JSONArray 186 ) -> collections.Sequence[user.UserCredentials]: 187 return [ 188 user.UserCredentials( 189 type=enums.CredentialType(int(creds["credentialType"])), 190 display_name=creds["credentialDisplayName"], 191 is_public=creds["isPublic"], 192 self_as_string=creds.get("credentialAsString", undefined.Undefined), 193 ) 194 for creds in payload 195 ]
Deserialize a JSON array of Bungie user credentials.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of user's credentials.
197 @staticmethod 198 def set_themese_attrs( 199 payload: typedefs.JSONArray, / 200 ) -> typing.Collection[user.UserThemes]: 201 return [ 202 user.UserThemes( 203 id=int(entry["userThemeId"]), 204 name=entry["userThemeName"] 205 if "userThemeName" in entry 206 else undefined.Undefined, 207 description=entry["userThemeDescription"] 208 if "userThemeDescription" in entry 209 else undefined.Undefined, 210 ) 211 for entry in payload 212 ]
214 def deserialize_user_themes( 215 self, payload: typedefs.JSONArray 216 ) -> collections.Sequence[user.UserThemes]: 217 return list(self.set_themese_attrs(payload))
Deserialize a raw JSON array of Bungie user themes.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
219 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 220 221 # This is kinda redundant 222 data = payload 223 224 # This is always outside the details. 225 current_user_map: typing.Optional[ 226 collections.Mapping[str, clans.ClanMember] 227 ] = None 228 if raw_current_user_map := payload.get("currentUserMemberMap"): 229 current_user_map = { 230 membership_type: self.deserialize_clan_member(membership) 231 for membership_type, membership in raw_current_user_map.items() 232 } 233 234 try: 235 data = payload["detail"] 236 except KeyError: 237 pass 238 239 id = data["groupId"] 240 name = data["name"] 241 created_at = data["creationDate"] 242 member_count = data["memberCount"] 243 about = data["about"] 244 motto = data["motto"] 245 is_public = data["isPublic"] 246 banner = assets.Image(str(data["bannerPath"])) 247 avatar = assets.Image(str(data["avatarPath"])) 248 tags = data["tags"] 249 type = data["groupType"] 250 251 features = data["features"] 252 features_obj = clans.ClanFeatures( 253 max_members=features["maximumMembers"], 254 max_membership_types=features["maximumMembershipsOfGroupType"], 255 capabilities=features["capabilities"], 256 membership_types=features["membershipTypes"], 257 invite_permissions=features["invitePermissionOverride"], 258 update_banner_permissions=features["updateBannerPermissionOverride"], 259 update_culture_permissions=features["updateCulturePermissionOverride"], 260 join_level=features["joinLevel"], 261 ) 262 263 information: typedefs.JSONObject = data["clanInfo"] 264 progression: collections.Mapping[int, progressions.Progression] = { 265 int(prog_hash): self.deserialize_progressions(prog) 266 for prog_hash, prog in information["d2ClanProgressions"].items() 267 } 268 269 founder: typedefs.NoneOr[clans.ClanMember] = None 270 if raw_founder := payload.get("founder"): 271 founder = self.deserialize_clan_member(raw_founder) 272 273 return clans.Clan( 274 net=self._net, 275 id=int(id), 276 name=name, 277 type=enums.GroupType(type), 278 created_at=time.clean_date(created_at), 279 member_count=member_count, 280 motto=motto, 281 about=about, 282 is_public=is_public, 283 banner=banner, 284 avatar=avatar, 285 tags=tags, 286 features=features_obj, 287 owner=founder, 288 progressions=progression, 289 call_sign=information["clanCallsign"], 290 banner_data=information["clanBannerData"], 291 chat_security=data["chatSecurity"], 292 conversation_id=int(data["conversationId"]), 293 allow_chat=data["allowChat"], 294 theme=data["theme"], 295 current_user_membership=current_user_map, 296 )
Deserialize a raw JSON payload of Bungie clan information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Clan: A clan owner.
298 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 299 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 300 return clans.ClanMember( 301 net=self._net, 302 last_seen_name=destiny_user.last_seen_name, 303 id=destiny_user.id, 304 name=destiny_user.name, 305 icon=destiny_user.icon, 306 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 307 group_id=int(data["groupId"]), 308 joined_at=time.clean_date(data["joinDate"]), 309 types=destiny_user.types, 310 is_public=destiny_user.is_public, 311 type=destiny_user.type, 312 code=destiny_user.code, 313 is_online=data["isOnline"], 314 crossave_override=destiny_user.crossave_override, 315 bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 316 if "bungieNetUserInfo" in data 317 else None, 318 member_type=enums.ClanMemberType(int(data["memberType"])), 319 )
Deserialize a JSON payload of a clan member information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ClanMember: A clan member.
321 def deserialize_clan_members( 322 self, data: typedefs.JSONObject, / 323 ) -> iterators.FlatIterator[clans.ClanMember]: 324 return iterators.FlatIterator( 325 [self.deserialize_clan_member(member) for member in data["results"]] 326 )
Deserialize a JSON payload of a clan members information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]: An iterator of clan members of the deserialized payload.
328 def deserialize_group_member( 329 self, payload: typedefs.JSONObject 330 ) -> clans.GroupMember: 331 member = payload["member"] 332 return clans.GroupMember( 333 net=self._net, 334 join_date=time.clean_date(member["joinDate"]), 335 group_id=int(member["groupId"]), 336 member_type=enums.ClanMemberType(member["memberType"]), 337 is_online=member["isOnline"], 338 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 339 inactive_memberships=payload.get("areAllMembershipsInactive", None), 340 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 341 group=self.deserialize_clan(payload["group"]), 342 )
Deserialize a JSON payload of group information for a member.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.typedefs.NoneOr[aiobungie.crates.GroupMember]: A group member. This can returnNoneif nothing was found.
360 def deserialize_clan_conversations( 361 self, payload: typedefs.JSONArray 362 ) -> collections.Sequence[clans.ClanConversation]: 363 return [self._deserialize_clan_conversation(conv) for conv in payload]
Deserialize a JSON array of a clan conversations information.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of clan conversations of the deserialized payload.
365 def deserialize_app_owner( 366 self, payload: typedefs.JSONObject 367 ) -> application.ApplicationOwner: 368 return application.ApplicationOwner( 369 net=self._net, 370 name=payload.get("bungieGlobalDisplayName", undefined.Undefined), 371 id=int(payload["membershipId"]), 372 type=enums.MembershipType(payload["membershipType"]), 373 icon=assets.Image(str(payload["iconPath"])), 374 is_public=payload["isPublic"], 375 code=payload.get("bungieGlobalDisplayNameCode", None), 376 )
Deserialize a JSON payload of Bungie Developer portal application owner information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.ApplicationOwner: An application owner.
378 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 379 return application.Application( 380 id=int(payload["applicationId"]), 381 name=payload["name"], 382 link=payload["link"], 383 status=payload["status"], 384 redirect_url=payload.get("redirectUrl", None), 385 created_at=time.clean_date(str(payload["creationDate"])), 386 published_at=time.clean_date(str(payload["firstPublished"])), 387 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 388 scope=payload.get("scope", undefined.Undefined), 389 )
Deserialize a JSON payload of Bungie Developer portal application information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.Application: An application.
412 def deserialize_profile( 413 self, payload: typedefs.JSONObject, / 414 ) -> typing.Optional[profile.Profile]: 415 if (raw_profile := payload.get("data")) is None: 416 return None 417 418 payload = raw_profile 419 id = int(payload["userInfo"]["membershipId"]) 420 name = payload["userInfo"]["displayName"] 421 is_public = payload["userInfo"]["isPublic"] 422 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 423 last_played = time.clean_date(str(payload["dateLastPlayed"])) 424 character_ids = [int(cid) for cid in payload["characterIds"]] 425 power_cap = payload["currentSeasonRewardPowerCap"] 426 427 return profile.Profile( 428 id=int(id), 429 name=name, 430 is_public=is_public, 431 type=type, 432 last_played=last_played, 433 character_ids=character_ids, 434 power_cap=power_cap, 435 net=self._net, 436 )
Deserialize a JSON payload of Bungie.net profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
typing.Optional[aiobungie.crates.Profile]: A profile.
438 def deserialize_profile_item( 439 self, payload: typedefs.JSONObject 440 ) -> profile.ProfileItemImpl: 441 442 instance_id: typing.Optional[int] = None 443 if raw_instance_id := payload.get("itemInstanceId"): 444 instance_id = int(raw_instance_id) 445 446 version_number: typing.Optional[int] = None 447 if raw_version := payload.get("versionNumber"): 448 version_number = int(raw_version) 449 450 transfer_status = enums.TransferStatus(payload["transferStatus"]) 451 452 return profile.ProfileItemImpl( 453 net=self._net, 454 hash=payload["itemHash"], 455 quantity=payload["quantity"], 456 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 457 location=enums.ItemLocation(payload["location"]), 458 bucket=payload["bucketHash"], 459 transfer_status=transfer_status, 460 lockable=payload["lockable"], 461 state=enums.ItemState(payload["state"]), 462 dismantel_permissions=payload["dismantlePermission"], 463 is_wrapper=payload["isWrapper"], 464 instance_id=instance_id, 465 version_number=version_number, 466 ornament_id=payload.get("overrideStyleItemHash"), 467 )
Deserialize a JSON payload of a singular profile component item.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ProfileItemImpl: Implementation of a Destiny 2 profile component item.
469 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 470 return records.Objective( 471 net=self._net, 472 hash=payload["objectiveHash"], 473 visible=payload["visible"], 474 complete=payload["complete"], 475 completion_value=payload["completionValue"], 476 progress=payload.get("progress"), 477 destination_hash=payload.get("destinationHash"), 478 activity_hash=payload.get("activityHash"), 479 )
Deserialize a JSON payload of an objective found in a record profile component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.records.Objective: A record objective object.
481 def deserialize_records( 482 self, 483 payload: typedefs.JSONObject, 484 scores: typing.Optional[records.RecordScores] = None, 485 **nodes: int, 486 ) -> records.Record: 487 objectives: typing.Optional[list[records.Objective]] = None 488 interval_objectives: typing.Optional[list[records.Objective]] = None 489 record_state: typedefs.IntAnd[records.RecordState] 490 491 record_state = records.RecordState(payload["state"]) 492 493 if raw_objs := payload.get("objectives"): 494 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 495 496 if raw_interval_objs := payload.get("intervalObjectives"): 497 interval_objectives = [ 498 self.deserialize_objectives(obj) for obj in raw_interval_objs 499 ] 500 501 return records.Record( 502 scores=scores, 503 categories_node_hash=nodes.get("categories_hash", undefined.Undefined), 504 seals_node_hash=nodes.get("seals_hash", undefined.Undefined), 505 state=record_state, 506 objectives=objectives, 507 interval_objectives=interval_objectives, 508 redeemed_count=payload.get("intervalsRedeemedCount", 0), 509 completion_times=payload.get("completedCount", None), 510 reward_visibility=payload.get("rewardVisibilty", None), 511 )
Deserialize a JSON object of a profile record component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload - scores (
typing.Optional[records.RecordScores]): The records scores object. This exists only to keep the signature ofaiobungie.crates.CharacterRecordwith the record object. As it will always beNonein that object. - **nodes (
int): An int kwargs use to grab the node hashes while deserializing components.
Returns
aiobungie.records.Record: A standard implementation of a profile record component.
513 def deserialize_character_records( 514 self, 515 payload: typedefs.JSONObject, 516 scores: typing.Optional[records.RecordScores] = None, 517 record_hashes: typing.Optional[list[int]] = None, 518 ) -> records.CharacterRecord: 519 520 record = self.deserialize_records(payload, scores) 521 return records.CharacterRecord( 522 scores=scores, 523 categories_node_hash=record.categories_node_hash, 524 seals_node_hash=record.seals_node_hash, 525 state=record.state, 526 objectives=record.objectives, 527 interval_objectives=record.interval_objectives, 528 redeemed_count=payload.get("intervalsRedeemedCount", 0), 529 completion_times=payload.get("completedCount"), 530 reward_visibility=payload.get("rewardVisibilty"), 531 record_hashes=record_hashes or [], 532 )
Deserialize a JSON object of a profile character record component.
This almost does the same this as deserialize_records but
has more fields which can only be found in a character record.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
534 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 535 return character.Dye( 536 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 537 )
Deserialize a JSON payload of a character's dye information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.Dye: Information about a character dye object.
539 def deserialize_character_customization( 540 self, payload: typedefs.JSONObject 541 ) -> character.CustomizationOptions: 542 return character.CustomizationOptions( 543 personality=payload["personality"], 544 face=payload["face"], 545 skin_color=payload["skinColor"], 546 lip_color=payload["lipColor"], 547 eye_color=payload["eyeColor"], 548 hair_colors=payload.get("hairColors", []), 549 feature_colors=payload.get("featureColors", []), 550 decal_color=payload["decalColor"], 551 wear_helmet=payload["wearHelmet"], 552 hair_index=payload["hairIndex"], 553 feature_index=payload["featureIndex"], 554 decal_index=payload["decalIndex"], 555 )
Deserialize a JSON payload of a character customization information found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
557 def deserialize_character_minimal_equipments( 558 self, payload: typedefs.JSONObject 559 ) -> character.MinimalEquipments: 560 dyes = None 561 if raw_dyes := payload.get("dyes"): 562 if raw_dyes: 563 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 564 return character.MinimalEquipments( 565 net=self._net, item_hash=payload["itemHash"], dyes=dyes 566 )
Deserialize a singular JSON peer view of equipment found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
568 def deserialize_character_render_data( 569 self, payload: typedefs.JSONObject, / 570 ) -> character.RenderedData: 571 return character.RenderedData( 572 net=self._net, 573 customization=self.deserialize_character_customization( 574 payload["customization"] 575 ), 576 custom_dyes=[ 577 self.deserialize_character_dye(dye) 578 for dye in payload["customDyes"] 579 if dye 580 ], 581 equipment=[ 582 self.deserialize_character_minimal_equipments(equipment) 583 for equipment in payload["peerView"]["equipment"] 584 ], 585 )
Deserialize a JSON payload of a profile character render data component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.RenderedData: A character rendered data profile component.
587 def deserialize_available_activity( 588 self, payload: typedefs.JSONObject 589 ) -> activity.AvailableActivity: 590 return activity.AvailableActivity( 591 hash=payload["activityHash"], 592 is_new=payload["isNew"], 593 is_completed=payload["isCompleted"], 594 is_visible=payload["isVisible"], 595 display_level=payload.get("displayLevel"), 596 recommended_light=payload.get("recommendedLight"), 597 difficulty=activity.Difficulty(payload["difficultyTier"]), 598 can_join=payload["canJoin"], 599 can_lead=payload["canLead"], 600 )
Deserialize a JSON payload of an available activities.
This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AvailableActivity: An available activity object.
602 def deserialize_character_activity( 603 self, payload: typedefs.JSONObject 604 ) -> activity.CharacterActivity: 605 current_mode: typing.Optional[enums.GameMode] = None 606 if raw_current_mode := payload.get("currentActivityModeType"): 607 current_mode = enums.GameMode(raw_current_mode) 608 609 current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None 610 if raw_current_modes := payload.get("currentActivityModeTypes"): 611 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 612 613 return activity.CharacterActivity( 614 date_started=time.clean_date(payload["dateActivityStarted"]), 615 current_hash=payload["currentActivityHash"], 616 current_mode_hash=payload["currentActivityModeHash"], 617 current_mode=current_mode, 618 current_mode_hashes=payload.get("currentActivityModeHashes"), 619 current_mode_types=current_mode_types, 620 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 621 last_story_hash=payload["lastCompletedStoryHash"], 622 available_activities=[ 623 self.deserialize_available_activity(activity_) 624 for activity_ in payload["availableActivities"] 625 ], 626 )
Deserialize a JSON payload of character activity profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterActivity: A character activities component object.
628 def deserialize_profile_items( 629 self, payload: typedefs.JSONObject, / 630 ) -> list[profile.ProfileItemImpl]: 631 return [self.deserialize_profile_item(item) for item in payload["items"]]
Deserialize a JSON payload of profile items component information.
This may deserialize profileInventories or profileCurrencies or any
other alternatives.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
typing.Optional[collections.Sequence[aiobungie.crates.ProfileItemImpl]]: A profile component object that contains items of the deserialized payload.
674 def deserialize_progressions( 675 self, payload: typedefs.JSONObject 676 ) -> progressions.Progression: 677 return progressions.Progression( 678 hash=int(payload["progressionHash"]), 679 level=int(payload["level"]), 680 cap=int(payload["levelCap"]), 681 daily_limit=int(payload["dailyLimit"]), 682 weekly_limit=int(payload["weeklyLimit"]), 683 current_progress=int(payload["currentProgress"]), 684 daily_progress=int(payload["dailyProgress"]), 685 needed=int(payload["progressToNextLevel"]), 686 next_level=int(payload["nextLevelAt"]), 687 )
775 def deserialize_milestone( 776 self, payload: typedefs.JSONObject 777 ) -> milestones.Milestone: 778 start_date: typing.Optional[datetime.datetime] = None 779 if raw_start_date := payload.get("startDate"): 780 start_date = time.clean_date(raw_start_date) 781 782 end_date: typing.Optional[datetime.datetime] = None 783 if raw_end_date := payload.get("endDate"): 784 end_date = time.clean_date(raw_end_date) 785 786 rewards: typing.Optional[ 787 collections.Collection[milestones.MilestoneReward] 788 ] = None 789 if raw_rewards := payload.get("rewards"): 790 rewards = [ 791 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 792 ] 793 794 activities: typing.Optional[ 795 collections.Sequence[milestones.MilestoneActivity] 796 ] = None 797 if raw_activities := payload.get("activities"): 798 activities = [ 799 self._deserialize_milestone_activity(active) 800 for active in raw_activities 801 ] 802 803 quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None 804 if raw_quests := payload.get("availableQuests"): 805 quests = [ 806 self._deserialize_milestone_available_quest(quest) 807 for quest in raw_quests 808 ] 809 810 vendors: typing.Optional[ 811 collections.Sequence[milestones.MilestoneVendor] 812 ] = None 813 if raw_vendors := payload.get("vendors"): 814 vendors = [ 815 milestones.MilestoneVendor( 816 vendor_hash=vendor["vendorHash"], 817 preview_itemhash=vendor.get("previewItemHash"), 818 ) 819 for vendor in raw_vendors 820 ] 821 822 return milestones.Milestone( 823 hash=payload["milestoneHash"], 824 start_date=start_date, 825 end_date=end_date, 826 order=payload["order"], 827 rewards=rewards, 828 available_quests=quests, 829 activities=activities, 830 vendors=vendors, 831 )
885 def deserialize_character_progressions( 886 self, payload: typedefs.JSONObject 887 ) -> character.CharacterProgression: 888 progressions_ = { 889 int(prog_id): self.deserialize_progressions(prog) 890 for prog_id, prog in payload["progressions"].items() 891 } 892 893 factions = { 894 int(faction_id): self._deserialize_factions(faction) 895 for faction_id, faction in payload["factions"].items() 896 } 897 898 milestones_ = { 899 int(milestone_hash): self.deserialize_milestone(milestone) 900 for milestone_hash, milestone in payload["milestones"].items() 901 } 902 903 uninstanced_item_objectives = { 904 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 905 for item_hash, obj in payload["uninstancedItemObjectives"].items() 906 } 907 908 artifact = payload["seasonalArtifact"] 909 seasonal_artifact = season.CharacterScopedArtifact( 910 hash=artifact["artifactHash"], 911 points_used=artifact["pointsUsed"], 912 reset_count=artifact["resetCount"], 913 tiers=[ 914 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 915 ], 916 ) 917 checklists = payload["checklists"] 918 919 return character.CharacterProgression( 920 progressions=progressions_, 921 factions=factions, 922 checklists=checklists, 923 milestones=milestones_, 924 seasonal_artifact=seasonal_artifact, 925 uninstanced_item_objectives=uninstanced_item_objectives, 926 )
928 def deserialize_character_progressions_mapping( 929 self, payload: typedefs.JSONObject 930 ) -> collections.Mapping[int, character.CharacterProgression]: 931 character_progressions: collections.Mapping[ 932 int, character.CharacterProgression 933 ] = {} 934 for char_id, data in payload["data"].items(): 935 # A little hack to stop mypy complaining about Mapping <-> dict 936 character_progressions[int(char_id)] = self.deserialize_character_progressions(data) # type: ignore[index] 937 return character_progressions
939 def deserialize_characters_records( 940 self, 941 payload: typedefs.JSONObject, 942 ) -> collections.Mapping[int, records.CharacterRecord]: 943 944 return { 945 int(rec_id): self.deserialize_character_records( 946 rec, record_hashes=payload.get("featuredRecordHashes") 947 ) 948 for rec_id, rec in payload["records"].items() 949 }
951 def deserialize_profile_records( 952 self, payload: typedefs.JSONObject 953 ) -> collections.Mapping[int, records.Record]: 954 raw_profile_records = payload["data"] 955 scores = records.RecordScores( 956 current_score=raw_profile_records["score"], 957 legacy_score=raw_profile_records["legacyScore"], 958 lifetime_score=raw_profile_records["lifetimeScore"], 959 ) 960 return { 961 int(record_id): self.deserialize_records( 962 record, 963 scores, 964 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 965 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 966 ) 967 for record_id, record in raw_profile_records["records"].items() 968 }
1005 def deserialize_craftables_component( 1006 self, payload: typedefs.JSONObject 1007 ) -> components.CraftablesComponent: 1008 return components.CraftablesComponent( 1009 net=self._net, 1010 craftables={ 1011 int(item_id): self._deserialize_craftable_item(item) 1012 for item_id, item in payload["craftables"].items() 1013 if item is not None 1014 }, 1015 crafting_root_node_hash=payload["craftingRootNodeHash"], 1016 )
1018 def deserialize_components( # noqa: C901 Too complex. 1019 self, payload: typedefs.JSONObject 1020 ) -> components.Component: 1021 1022 profile_: typing.Optional[profile.Profile] = None 1023 if raw_profile := payload.get("profile"): 1024 profile_ = self.deserialize_profile(raw_profile) 1025 1026 profile_progression: typing.Optional[profile.ProfileProgression] = None 1027 if raw_profile_progression := payload.get("profileProgression"): 1028 profile_progression = self.deserialize_profile_progression( 1029 raw_profile_progression 1030 ) 1031 1032 profile_currencies: typing.Optional[ 1033 collections.Sequence[profile.ProfileItemImpl] 1034 ] = None 1035 if raw_profile_currencies := payload.get("profileCurrencies"): 1036 if "data" in raw_profile_currencies: 1037 profile_currencies = self.deserialize_profile_items( 1038 raw_profile_currencies["data"] 1039 ) 1040 1041 profile_inventories: typing.Optional[ 1042 collections.Sequence[profile.ProfileItemImpl] 1043 ] = None 1044 if raw_profile_inventories := payload.get("profileInventory"): 1045 if "data" in raw_profile_inventories: 1046 profile_inventories = self.deserialize_profile_items( 1047 raw_profile_inventories["data"] 1048 ) 1049 1050 profile_records: typing.Optional[ 1051 collections.Mapping[int, records.Record] 1052 ] = None 1053 1054 if raw_profile_records_ := payload.get("profileRecords"): 1055 profile_records = self.deserialize_profile_records(raw_profile_records_) 1056 1057 characters: typing.Optional[typing.Mapping[int, character.Character]] = None 1058 if raw_characters := payload.get("characters"): 1059 characters = self.deserialize_characters(raw_characters) 1060 1061 character_records: typing.Optional[ 1062 collections.Mapping[int, records.CharacterRecord] 1063 ] = None 1064 1065 if raw_character_records := payload.get("characterRecords"): 1066 # Had to do it in two steps.. 1067 to_update: typedefs.JSONObject = {} 1068 for _, data in raw_character_records["data"].items(): 1069 for record_id, record in data.items(): 1070 to_update[record_id] = record 1071 1072 character_records = { 1073 int(rec_id): self.deserialize_character_records( 1074 rec, record_hashes=to_update.get("featuredRecordHashes") 1075 ) 1076 for rec_id, rec in to_update["records"].items() 1077 } 1078 1079 character_equipments: typing.Optional[ 1080 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1081 ] = None 1082 if raw_character_equips := payload.get("characterEquipment"): 1083 character_equipments = self.deserialize_character_equipments( 1084 raw_character_equips 1085 ) 1086 1087 character_inventories: typing.Optional[ 1088 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1089 ] = None 1090 if raw_character_inventories := payload.get("characterInventories"): 1091 if "data" in raw_character_inventories: 1092 character_inventories = self.deserialize_character_equipments( 1093 raw_character_inventories 1094 ) 1095 1096 character_activities: typing.Optional[ 1097 collections.Mapping[int, activity.CharacterActivity] 1098 ] = None 1099 if raw_char_acts := payload.get("characterActivities"): 1100 character_activities = self.deserialize_character_activities(raw_char_acts) 1101 1102 character_render_data: typing.Optional[ 1103 collections.Mapping[int, character.RenderedData] 1104 ] = None 1105 if raw_character_render_data := payload.get("characterRenderData"): 1106 character_render_data = self.deserialize_characters_render_data( 1107 raw_character_render_data 1108 ) 1109 1110 character_progressions: typing.Optional[ 1111 collections.Mapping[int, character.CharacterProgression] 1112 ] = None 1113 1114 if raw_character_progressions := payload.get("characterProgressions"): 1115 character_progressions = self.deserialize_character_progressions_mapping( 1116 raw_character_progressions 1117 ) 1118 1119 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1120 if raw_profile_string_vars := payload.get("profileStringVariables"): 1121 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1122 1123 character_string_vars: typing.Optional[ 1124 collections.Mapping[int, collections.Mapping[int, int]] 1125 ] = None 1126 if raw_character_string_vars := payload.get("characterStringVariables"): 1127 character_string_vars = { 1128 int(char_id): data["integerValuesByHash"] 1129 for char_id, data in raw_character_string_vars["data"].items() 1130 } 1131 1132 metrics: typing.Optional[ 1133 collections.Sequence[ 1134 collections.Mapping[ 1135 int, tuple[bool, typing.Optional[records.Objective]] 1136 ] 1137 ] 1138 ] = None 1139 root_node_hash: typing.Optional[int] = None 1140 1141 if raw_metrics := payload.get("metrics"): 1142 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1143 metrics = [ 1144 { 1145 int(metrics_hash): ( 1146 data["invisible"], 1147 self.deserialize_objectives(data["objectiveProgress"]) 1148 if "objectiveProgress" in data 1149 else None, 1150 ) 1151 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1152 } 1153 ] 1154 transitory: typing.Optional[fireteams.FireteamParty] = None 1155 if raw_transitory := payload.get("profileTransitoryData"): 1156 if "data" in raw_transitory: 1157 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1158 1159 item_components: typing.Optional[components.ItemsComponent] = None 1160 if raw_item_components := payload.get("itemComponents"): 1161 item_components = self.deserialize_items_component(raw_item_components) 1162 1163 profile_plugsets: typing.Optional[ 1164 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1165 ] = None 1166 1167 if raw_profile_plugs := payload.get("profilePlugSets"): 1168 profile_plugsets = { 1169 int(index): [self.deserialize_plug_item_state(state) for state in data] 1170 for index, data in raw_profile_plugs["data"]["plugs"].items() 1171 } 1172 1173 character_plugsets: typing.Optional[ 1174 collections.Mapping[ 1175 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1176 ] 1177 ] = None 1178 if raw_char_plugsets := payload.get("characterPlugSets"): 1179 character_plugsets = { 1180 int(char_id): { 1181 int(index): [ 1182 self.deserialize_plug_item_state(state) for state in data 1183 ] 1184 for index, data in inner["plugs"].items() 1185 } 1186 for char_id, inner in raw_char_plugsets["data"].items() 1187 } 1188 1189 character_collectibles: typing.Optional[ 1190 collections.Mapping[int, items.Collectible] 1191 ] = None 1192 if raw_character_collectibles := payload.get("characterCollectibles"): 1193 character_collectibles = { 1194 int(char_id): self._deserialize_collectible(data) 1195 for char_id, data in raw_character_collectibles["data"].items() 1196 } 1197 1198 profile_collectibles: typing.Optional[items.Collectible] = None 1199 if raw_profile_collectibles := payload.get("profileCollectibles"): 1200 profile_collectibles = self._deserialize_collectible( 1201 raw_profile_collectibles["data"] 1202 ) 1203 1204 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1205 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1206 profile_nodes = { 1207 int(node_hash): self._deserialize_node(node) 1208 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1209 } 1210 1211 character_nodes: typing.Optional[ 1212 collections.Mapping[int, collections.Mapping[int, records.Node]] 1213 ] = None 1214 if raw_character_nodes := payload.get("characterPresentationNodes"): 1215 character_nodes = { 1216 int(char_id): { 1217 int(node_hash): self._deserialize_node(node) 1218 for node_hash, node in each_character["nodes"].items() 1219 } 1220 for char_id, each_character in raw_character_nodes["data"].items() 1221 } 1222 1223 platform_silver: typing.Optional[ 1224 collections.Mapping[str, profile.ProfileItemImpl] 1225 ] = None 1226 if raw_platform_silver := payload.get("platformSilver"): 1227 if "data" in raw_platform_silver: 1228 platform_silver = { 1229 platform_name: self.deserialize_profile_item(item) 1230 for platform_name, item in raw_platform_silver["data"][ 1231 "platformSilver" 1232 ].items() 1233 } 1234 1235 character_currency_lookups: typing.Optional[ 1236 collections.Mapping[int, collections.Sequence[items.Currency]] 1237 ] = None 1238 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1239 if "data" in raw_char_lookups: 1240 character_currency_lookups = { 1241 int(char_id): self._deserialize_currencies(currencie) 1242 for char_id, currencie in raw_char_lookups["data"].items() 1243 } 1244 1245 character_craftables: typing.Optional[ 1246 collections.Mapping[int, components.CraftablesComponent] 1247 ] = None 1248 if raw_character_craftables := payload.get("characterCraftables"): 1249 1250 if "data" in raw_character_craftables: 1251 character_craftables = { 1252 int(char_id): self.deserialize_craftables_component(craftable) 1253 for char_id, craftable in raw_character_craftables["data"].items() 1254 } 1255 1256 return components.Component( 1257 profiles=profile_, 1258 profile_progression=profile_progression, 1259 profile_currencies=profile_currencies, 1260 profile_inventories=profile_inventories, 1261 profile_records=profile_records, 1262 characters=characters, 1263 character_records=character_records, 1264 character_equipments=character_equipments, 1265 character_inventories=character_inventories, 1266 character_activities=character_activities, 1267 character_render_data=character_render_data, 1268 character_progressions=character_progressions, 1269 profile_string_variables=profile_string_vars, 1270 character_string_variables=character_string_vars, 1271 metrics=metrics, 1272 root_node_hash=root_node_hash, 1273 transitory=transitory, 1274 item_components=item_components, 1275 profile_plugsets=profile_plugsets, 1276 character_plugsets=character_plugsets, 1277 character_collectibles=character_collectibles, 1278 profile_collectibles=profile_collectibles, 1279 profile_nodes=profile_nodes, 1280 character_nodes=character_nodes, 1281 platform_silver=platform_silver, 1282 character_currency_lookups=character_currency_lookups, 1283 character_craftables=character_craftables, 1284 )
Deserialize a JSON payload of Bungie.net profile components information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Component: A component implementation that includes all other components of the deserialized payload.
1286 def deserialize_items_component( 1287 self, payload: typedefs.JSONObject 1288 ) -> components.ItemsComponent: 1289 instances: typing.Optional[ 1290 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1291 ] = None 1292 if raw_instances := payload.get("instances"): 1293 instances = [ 1294 { 1295 int(ins_id): self.deserialize_instanced_item(item) 1296 for ins_id, item in raw_instances["data"].items() 1297 } 1298 ] 1299 1300 render_data: typing.Optional[ 1301 collections.Mapping[int, tuple[bool, dict[int, int]]] 1302 ] = None 1303 if raw_render_data := payload.get("renderData"): 1304 render_data = { 1305 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1306 for ins_id, data in raw_render_data["data"].items() 1307 } 1308 1309 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1310 if raw_stats := payload.get("stats"): 1311 builder: collections.Mapping[int, items.ItemStatsView] = {} 1312 for ins_id, stat in raw_stats["data"].items(): 1313 for _, items_ in stat.items(): 1314 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1315 stats = builder 1316 1317 sockets: typing.Optional[ 1318 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1319 ] = None 1320 if raw_sockets := payload.get("sockets"): 1321 sockets = { 1322 int(ins_id): [ 1323 self.deserialize_item_socket(socket) for socket in item["sockets"] 1324 ] 1325 for ins_id, item in raw_sockets["data"].items() 1326 } 1327 1328 objeectives: typing.Optional[ 1329 collections.Mapping[int, collections.Sequence[records.Objective]] 1330 ] = None 1331 if raw_objectives := payload.get("objectives"): 1332 objeectives = { 1333 int(ins_id): [self.deserialize_objectives(objective)] 1334 for ins_id, data in raw_objectives["data"].items() 1335 for objective in data["objectives"] 1336 } 1337 1338 perks: typing.Optional[ 1339 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1340 ] = None 1341 if raw_perks := payload.get("perks"): 1342 perks = { 1343 int(ins_id): [ 1344 self.deserialize_item_perk(perk) for perk in item["perks"] 1345 ] 1346 for ins_id, item in raw_perks["data"].items() 1347 } 1348 1349 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1350 if raw_plug_states := payload.get("plugStates"): 1351 pending_states: list[items.PlugItemState] = [] 1352 for _, plug in raw_plug_states["data"].items(): 1353 pending_states.append(self.deserialize_plug_item_state(plug)) 1354 plug_states = pending_states 1355 1356 reusable_plugs: typing.Optional[ 1357 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1358 ] = None 1359 if raw_re_plugs := payload.get("reusablePlugs"): 1360 reusable_plugs = { 1361 int(ins_id): [ 1362 self.deserialize_plug_item_state(state) for state in inner 1363 ] 1364 for ins_id, plug in raw_re_plugs["data"].items() 1365 for inner in list(plug["plugs"].values()) 1366 } 1367 1368 plug_objectives: typing.Optional[ 1369 collections.Mapping[ 1370 int, collections.Mapping[int, collections.Collection[records.Objective]] 1371 ] 1372 ] = None 1373 if raw_plug_objectives := payload.get("plugObjectives"): 1374 plug_objectives = { 1375 int(ins_id): { 1376 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1377 for obj_hash, objs in inner["objectivesPerPlug"].items() 1378 } 1379 for ins_id, inner in raw_plug_objectives["data"].items() 1380 } 1381 1382 return components.ItemsComponent( 1383 sockets=sockets, 1384 stats=stats, 1385 render_data=render_data, 1386 instances=instances, 1387 objectives=objeectives, 1388 perks=perks, 1389 plug_states=plug_states, 1390 reusable_plugs=reusable_plugs, 1391 plug_objectives=plug_objectives, 1392 )
Deserialize a JSON objects within the itemComponents key.`
1394 def deserialize_character_component( # type: ignore[call-arg] 1395 self, payload: typedefs.JSONObject 1396 ) -> components.CharacterComponent: 1397 1398 character_: typing.Optional[character.Character] = None 1399 if raw_singuler_character := payload.get("character"): 1400 character_ = self.deserialize_character(raw_singuler_character["data"]) 1401 1402 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1403 if raw_inventory := payload.get("inventory"): 1404 if "data" in raw_inventory: 1405 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1406 1407 activities: typing.Optional[activity.CharacterActivity] = None 1408 if raw_activities := payload.get("activities"): 1409 activities = self.deserialize_character_activity(raw_activities["data"]) 1410 1411 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1412 if raw_equipments := payload.get("equipment"): 1413 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1414 1415 progressions_: typing.Optional[character.CharacterProgression] = None 1416 if raw_progressions := payload.get("progressions"): 1417 progressions_ = self.deserialize_character_progressions( 1418 raw_progressions["data"] 1419 ) 1420 1421 render_data: typing.Optional[character.RenderedData] = None 1422 if raw_render_data := payload.get("renderData"): 1423 render_data = self.deserialize_character_render_data( 1424 raw_render_data["data"] 1425 ) 1426 1427 character_records: typing.Optional[ 1428 collections.Mapping[int, records.CharacterRecord] 1429 ] = None 1430 if raw_char_records := payload.get("records"): 1431 character_records = self.deserialize_characters_records( 1432 raw_char_records["data"] 1433 ) 1434 1435 item_components: typing.Optional[components.ItemsComponent] = None 1436 if raw_item_components := payload.get("itemComponents"): 1437 item_components = self.deserialize_items_component(raw_item_components) 1438 1439 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1440 if raw_nodes := payload.get("presentationNodes"): 1441 nodes = { 1442 int(node_hash): self._deserialize_node(node) 1443 for node_hash, node in raw_nodes["data"]["nodes"].items() 1444 } 1445 1446 collectibles: typing.Optional[items.Collectible] = None 1447 if raw_collectibles := payload.get("collectibles"): 1448 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1449 1450 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1451 if raw_currencies := payload.get("currencyLookups"): 1452 if "data" in raw_currencies: 1453 currency_lookups = self._deserialize_currencies(raw_currencies) 1454 1455 return components.CharacterComponent( 1456 activities=activities, 1457 equipment=equipment, 1458 inventory=inventory, 1459 progressions=progressions_, 1460 render_data=render_data, 1461 character=character_, 1462 character_records=character_records, 1463 profile_records=None, 1464 item_components=item_components, 1465 currency_lookups=currency_lookups, 1466 collectibles=collectibles, 1467 nodes=nodes, 1468 )
Deserialize a JSON payload of Destiny 2 character component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterComponent: A character component.
1496 def deserialize_inventory_results( 1497 self, payload: typedefs.JSONObject 1498 ) -> iterators.FlatIterator[entity.SearchableEntity]: 1499 suggested_words: list[str] = payload["suggestedWords"] 1500 1501 def _check_unknown(s: str) -> undefined.UndefinedOr[str]: 1502 return s if not typedefs.is_unknown(s) else undefined.Undefined 1503 1504 return iterators.FlatIterator( 1505 [ 1506 entity.SearchableEntity( 1507 net=self._net, 1508 hash=data["hash"], 1509 entity_type=data["entityType"], 1510 weight=data["weight"], 1511 suggested_words=suggested_words, 1512 name=data["displayProperties"]["name"], 1513 has_icon=data["displayProperties"]["hasIcon"], 1514 description=_check_unknown( 1515 data["displayProperties"]["description"] 1516 ), 1517 icon=assets.Image(data["displayProperties"]["icon"]), 1518 ) 1519 for data in payload["results"]["results"] 1520 ] 1521 )
Deserialize results of searched Destiny2 entities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]: An iterator over the found searched entities.
1550 def deserialize_inventory_entity( # noqa: C901 Too complex. 1551 self, payload: typedefs.JSONObject, / 1552 ) -> entity.InventoryEntity: 1553 1554 props = self._set_entity_attrs(payload) 1555 objects = self._deserialize_inventory_item_objects(payload) 1556 1557 collectible_hash: typing.Optional[int] = None 1558 if raw_collectible_hash := payload.get("collectibleHash"): 1559 collectible_hash = int(raw_collectible_hash) 1560 1561 secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1562 if raw_second_icon := payload.get("secondaryIcon"): 1563 secondary_icon = assets.Image(raw_second_icon) 1564 1565 secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1566 if raw_second_overlay := payload.get("secondaryOverlay"): 1567 secondary_overlay = assets.Image(raw_second_overlay) 1568 1569 secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1570 if raw_second_special := payload.get("secondarySpecial"): 1571 secondary_special = assets.Image(raw_second_special) 1572 1573 screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1574 if raw_screenshot := payload.get("screenshot"): 1575 screenshot = assets.Image(raw_screenshot) 1576 1577 watermark_icon: typing.Optional[assets.Image] = None 1578 if raw_watermark_icon := payload.get("iconWatermark"): 1579 watermark_icon = assets.Image(raw_watermark_icon) 1580 1581 watermark_shelved: typing.Optional[assets.Image] = None 1582 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1583 watermark_shelved = assets.Image(raw_watermark_shelved) 1584 1585 about: undefined.UndefinedOr[str] = undefined.Undefined 1586 if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown( 1587 raw_about 1588 ): 1589 about = raw_about 1590 1591 ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined 1592 if ( 1593 raw_ui_style := payload.get("uiItemDisplayStyle") 1594 ) and not typedefs.is_unknown(raw_ui_style): 1595 ui_item_style = raw_ui_style 1596 1597 tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined 1598 if ( 1599 raw_tier_and_name := payload.get("itemTypeAndTierDisplayName") 1600 ) and not typedefs.is_unknown(raw_tier_and_name): 1601 tier_and_name = raw_tier_and_name 1602 1603 type_name: undefined.UndefinedOr[str] = undefined.Undefined 1604 if ( 1605 raw_type_name := payload.get("itemTypeDisplayName") 1606 ) and not typedefs.is_unknown(raw_type_name): 1607 type_name = raw_type_name 1608 1609 display_source: undefined.UndefinedOr[str] = undefined.Undefined 1610 if ( 1611 raw_display_source := payload.get("displaySource") 1612 ) and not typedefs.is_unknown(raw_display_source): 1613 display_source = raw_display_source 1614 1615 lorehash: typing.Optional[int] = None 1616 if raw_lore_hash := payload.get("loreHash"): 1617 lorehash = int(raw_lore_hash) 1618 1619 summary_hash: typing.Optional[int] = None 1620 if raw_summary_hash := payload.get("summaryItemHash"): 1621 summary_hash = raw_summary_hash 1622 1623 breaker_type_hash: typing.Optional[int] = None 1624 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1625 breaker_type_hash = int(raw_breaker_type_hash) 1626 1627 damage_types: typing.Optional[collections.Sequence[int]] = None 1628 if raw_damage_types := payload.get("damageTypes"): 1629 damage_types = [int(type_) for type_ in raw_damage_types] 1630 1631 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1632 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1633 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1634 1635 default_damagetype_hash: typing.Optional[int] = None 1636 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1637 default_damagetype_hash = int(raw_defaultdmg_hash) 1638 1639 emblem_objective_hash: typing.Optional[int] = None 1640 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1641 emblem_objective_hash = int(raw_emblem_obj_hash) 1642 1643 tier_type: typing.Optional[enums.TierType] = None 1644 tier: typing.Optional[enums.ItemTier] = None 1645 bucket_hash: typing.Optional[int] = None 1646 recovery_hash: typing.Optional[int] = None 1647 tier_name: undefined.UndefinedOr[str] = undefined.Undefined 1648 isinstance_item: bool = False 1649 expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined 1650 expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined 1651 suppress_expiration: bool = False 1652 max_stack_size: typing.Optional[int] = None 1653 stack_label: undefined.UndefinedOr[str] = undefined.Undefined 1654 1655 if inventory := payload.get("inventory"): 1656 tier_type = enums.TierType(int(inventory["tierType"])) 1657 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1658 bucket_hash = int(inventory["bucketTypeHash"]) 1659 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1660 tier_name = inventory["tierTypeName"] 1661 isinstance_item = inventory["isInstanceItem"] 1662 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1663 max_stack_size = int(inventory["maxStackSize"]) 1664 1665 try: 1666 stack_label = inventory["stackUniqueLabel"] 1667 except KeyError: 1668 pass 1669 1670 return entity.InventoryEntity( 1671 net=self._net, 1672 collectible_hash=collectible_hash, 1673 name=props.name, 1674 about=about, 1675 emblem_objective_hash=emblem_objective_hash, 1676 suppress_expiration=suppress_expiration, 1677 max_stack_size=max_stack_size, 1678 stack_label=stack_label, 1679 tier=tier, 1680 tier_type=tier_type, 1681 tier_name=tier_name, 1682 bucket_hash=bucket_hash, 1683 recovery_bucket_hash=recovery_hash, 1684 isinstance_item=isinstance_item, 1685 expire_in_orbit_message=expire_in_orbit_message, 1686 expiration_tooltip=expire_tool_tip, 1687 lore_hash=lorehash, 1688 type_and_tier_name=tier_and_name, 1689 summary_hash=summary_hash, 1690 ui_display_style=ui_item_style, 1691 type_name=type_name, 1692 breaker_type_hash=breaker_type_hash, 1693 description=props.description, 1694 display_source=display_source, 1695 hash=props.hash, 1696 damage_types=damage_types, 1697 index=props.index, 1698 icon=props.icon, 1699 has_icon=props.has_icon, 1700 screenshot=screenshot, 1701 watermark_icon=watermark_icon, 1702 watermark_shelved=watermark_shelved, 1703 secondary_icon=secondary_icon, 1704 secondary_overlay=secondary_overlay, 1705 secondary_special=secondary_special, 1706 type=enums.ItemType(int(payload["itemType"])), 1707 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1708 trait_ids=[trait for trait in payload.get("traitIds", [])], 1709 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1710 item_class=enums.Class(int(payload["classType"])), 1711 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1712 breaker_type=int(payload["breakerType"]), 1713 default_damagetype=int(payload["defaultDamageType"]), 1714 default_damagetype_hash=default_damagetype_hash, 1715 damagetype_hashes=damagetype_hashes, 1716 tooltip_notifications=payload["tooltipNotifications"], 1717 not_transferable=payload["nonTransferrable"], 1718 allow_actions=payload["allowActions"], 1719 is_equippable=payload["equippable"], 1720 objects=objects, 1721 background_colors=payload.get("backgroundColor", {}), 1722 season_hash=payload.get("seasonHash"), 1723 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1724 )
Deserialize a JSON payload of an inventory entity item information.
This can be any item from DestinyInventoryItemDefinition definition.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.InventoryEntity: An entity item.
1726 def deserialize_objective_entity( 1727 self, payload: typedefs.JSONObject, / 1728 ) -> entity.ObjectiveEntity: 1729 props = self._set_entity_attrs(payload) 1730 return entity.ObjectiveEntity( 1731 net=self._net, 1732 hash=props.hash, 1733 index=props.index, 1734 description=props.description, 1735 name=props.name, 1736 has_icon=props.has_icon, 1737 icon=props.icon, 1738 unlock_value_hash=payload["unlockValueHash"], 1739 completion_value=payload["completionValue"], 1740 scope=entity.GatingScope(int(payload["scope"])), 1741 location_hash=payload["locationHash"], 1742 allowed_negative_value=payload["allowNegativeValue"], 1743 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1744 counting_downward=payload["isCountingDownward"], 1745 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1746 progress_description=payload["progressDescription"], 1747 perks=payload["perks"], 1748 stats=payload["stats"], 1749 minimum_visibility=payload["minimumVisibilityThreshold"], 1750 allow_over_completion=payload["allowOvercompletion"], 1751 show_value_style=payload["showValueOnComplete"], 1752 display_only_objective=payload["isDisplayOnlyObjective"], 1753 complete_value_style=entity.ValueUIStyle( 1754 int(payload["completedValueStyle"]) 1755 ), 1756 progress_value_style=entity.ValueUIStyle( 1757 int(payload["inProgressValueStyle"]) 1758 ), 1759 ui_label=payload["uiLabel"], 1760 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1761 )
Deserialize a JSON payload of an objective entity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity.
1789 def deserialize_activity( 1790 self, 1791 payload: typedefs.JSONObject, 1792 /, 1793 ) -> activity.Activity: 1794 period = time.clean_date(payload["period"]) 1795 details = payload["activityDetails"] 1796 ref_id = int(details["referenceId"]) 1797 instance_id = int(details["instanceId"]) 1798 mode = enums.GameMode(details["mode"]) 1799 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1800 is_private = details["isPrivate"] 1801 membership_type = enums.MembershipType(int(details["membershipType"])) 1802 1803 # Since we're using the same fields for post activity method 1804 # this check is required since post activity doesn't values values 1805 values = self._deserialize_activity_values(payload["values"]) 1806 1807 return activity.Activity( 1808 net=self._net, 1809 hash=ref_id, 1810 instance_id=instance_id, 1811 mode=mode, 1812 modes=modes, 1813 is_private=is_private, 1814 membership_type=membership_type, 1815 occurred_at=period, 1816 values=values, 1817 )
Deserialize a JSON payload of an activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Activity: An activity.
1819 def deserialize_activities( 1820 self, payload: typedefs.JSONObject 1821 ) -> iterators.FlatIterator[activity.Activity]: 1822 return iterators.FlatIterator( 1823 [ 1824 self.deserialize_activity(activity_) 1825 for activity_ in payload["activities"] 1826 ] 1827 )
Deserialize a JSON payload of an array of activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]: Am iterator over activity objects of the deserialized payload.
1829 def deserialize_extended_weapon_values( 1830 self, payload: typedefs.JSONObject 1831 ) -> activity.ExtendedWeaponValues: 1832 1833 assists: typing.Optional[int] = None 1834 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1835 assists = raw_assists["basic"]["value"] 1836 assists_damage: typing.Optional[int] = None 1837 1838 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1839 assists_damage = raw_assists_damage["basic"]["value"] 1840 1841 return activity.ExtendedWeaponValues( 1842 reference_id=int(payload["referenceId"]), 1843 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1844 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1845 "value" 1846 ], 1847 assists=assists, 1848 assists_damage=assists_damage, 1849 precision_kills_percentage=( 1850 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1851 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1852 "displayValue" 1853 ], 1854 ), 1855 )
Deserialize values of extended weapons JSON object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ExtendedWeaponValues: Information about an extended weapon values.
1878 def deserialize_post_activity_player( 1879 self, payload: typedefs.JSONObject, / 1880 ) -> activity.PostActivityPlayer: 1881 player = payload["player"] 1882 1883 class_hash: typedefs.NoneOr[int] = None 1884 if (class_hash := player.get("classHash")) is not None: 1885 class_hash = class_hash 1886 1887 race_hash: typedefs.NoneOr[int] = None 1888 if (race_hash := player.get("raceHash")) is not None: 1889 race_hash = race_hash 1890 1891 gender_hash: typedefs.NoneOr[int] = None 1892 if (gender_hash := player.get("genderHash")) is not None: 1893 gender_hash = gender_hash 1894 1895 character_class: undefined.UndefinedOr[str] = undefined.Undefined 1896 if ( 1897 character_class := player.get("characterClass") 1898 ) and not typedefs.is_unknown(character_class): 1899 character_class = character_class 1900 1901 character_level: typedefs.NoneOr[int] = None 1902 if (character_level := player.get("characterLevel")) is not None: 1903 character_level = character_level 1904 1905 return activity.PostActivityPlayer( 1906 standing=int(payload["standing"]), 1907 score=int(payload["score"]["basic"]["value"]), 1908 character_id=payload["characterId"], 1909 destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]), 1910 character_class=character_class, 1911 character_level=character_level, 1912 race_hash=race_hash, 1913 gender_hash=gender_hash, 1914 class_hash=class_hash, 1915 light_level=int(player["lightLevel"]), 1916 emblem_hash=int(player["emblemHash"]), 1917 values=self._deserialize_activity_values(payload["values"]), 1918 extended_values=self._deserialize_extended_values(payload["extended"]), 1919 )
Deserialize a JSON payload of a post activity player information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivityPlayer: A post activity player object.
1931 def deserialize_post_activity( 1932 self, payload: typedefs.JSONObject 1933 ) -> activity.PostActivity: 1934 period = time.clean_date(payload["period"]) 1935 details = payload["activityDetails"] 1936 ref_id = int(details["referenceId"]) 1937 instance_id = int(details["instanceId"]) 1938 mode = enums.GameMode(details["mode"]) 1939 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1940 is_private = details["isPrivate"] 1941 membership_type = enums.MembershipType(int(details["membershipType"])) 1942 return activity.PostActivity( 1943 net=self._net, 1944 hash=ref_id, 1945 membership_type=membership_type, 1946 instance_id=instance_id, 1947 mode=mode, 1948 modes=modes, 1949 is_private=is_private, 1950 occurred_at=period, 1951 starting_phase=int(payload["startingPhaseIndex"]), 1952 players=[ 1953 self.deserialize_post_activity_player(player) 1954 for player in payload["entries"] 1955 ], 1956 teams=[ 1957 self._deserialize_post_activity_team(team) for team in payload["teams"] 1958 ], 1959 )
Deserialize a JSON payload of a post activity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivity: A post activity object.
1997 def deserialize_aggregated_activity( 1998 self, payload: typedefs.JSONObject 1999 ) -> activity.AggregatedActivity: 2000 return activity.AggregatedActivity( 2001 hash=int(payload["activityHash"]), 2002 values=self._deserialize_aggregated_activity_values(payload["values"]), 2003 )
Deserialize a JSON payload of an aggregated activity.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AggregatedActivity: An aggregated activity object.
2005 def deserialize_aggregated_activities( 2006 self, payload: typedefs.JSONObject 2007 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 2008 return iterators.FlatIterator( 2009 [ 2010 self.deserialize_aggregated_activity(activity) 2011 for activity in payload["activities"] 2012 ] 2013 )
Deserialize a JSON payload of an array of aggregated activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]: An iterator over aggregated activities objects.
2015 def deserialize_linked_profiles( 2016 self, payload: typedefs.JSONObject 2017 ) -> profile.LinkedProfile: 2018 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 2019 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2020 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2021 2022 if raw_profile := payload.get("profiles"): 2023 for pfile in raw_profile: 2024 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 2025 2026 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 2027 for raw_error_pfile in raw_profiles_with_errors: 2028 if error_pfile := raw_error_pfile.get("infoCard"): 2029 error_profiles_vec.append( 2030 self.deserialize_destiny_membership(error_pfile) 2031 ) 2032 2033 return profile.LinkedProfile( 2034 net=self._net, 2035 bungie=bungie_user, 2036 profiles=profiles_vec, 2037 profiles_with_errors=error_profiles_vec, 2038 )
Deserialize a JSON payload of Bungie.net hard linked profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.LinkedProfile: A hard linked profile.
2054 def deserialize_public_milestone_content( 2055 self, payload: typedefs.JSONObject 2056 ) -> milestones.MilestoneContent: 2057 items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None 2058 if raw_categories := payload.get("itemCategories"): 2059 for item in raw_categories: 2060 title = undefined.Undefined 2061 if raw_title := item.get("title"): 2062 if raw_title != typedefs.Unknown: 2063 title = raw_title 2064 if raw_hashes := item.get("itemHashes"): 2065 hashes: collections.Sequence[int] = raw_hashes 2066 2067 items_categoris = milestones.MilestoneItems(title=title, hashes=hashes) 2068 2069 about = undefined.Undefined 2070 if (raw_about := payload["about"]) != typedefs.Unknown: 2071 about = raw_about 2072 2073 status = undefined.Undefined 2074 if (raw_status := payload["status"]) != typedefs.Unknown: 2075 status = raw_status 2076 2077 tips: typing.MutableSequence[undefined.UndefinedOr[str]] = [] 2078 if raw_tips := payload.get("tips"): 2079 for raw_tip in raw_tips: 2080 if raw_tip == typedefs.Unknown: 2081 raw_tip = undefined.Undefined 2082 tips.append(raw_tip) 2083 2084 return milestones.MilestoneContent( 2085 about=about, status=status, tips=tips, items=items_categoris 2086 )
Deserialize a JSON payload of milestone content information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.MilestoneContent: A milestone content.
2088 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2089 name = undefined.Undefined 2090 if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown: 2091 name = raw_name 2092 2093 bungie_user: typedefs.NoneOr[user.BungieUser] = None 2094 2095 if raw_bungie_user := payload.get("bungieNetUser"): 2096 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2097 2098 return friends.Friend( 2099 net=self._net, 2100 id=int(payload["lastSeenAsMembershipId"]), 2101 name=name, 2102 code=payload.get("bungieGlobalDisplayNameCode"), 2103 relationship=enums.Relationship(payload["relationship"]), 2104 user=bungie_user, 2105 online_status=enums.Presence(payload["onlineStatus"]), 2106 online_title=payload["onlineTitle"], 2107 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2108 )
Deserialize a JSON payload of a Bungie friend information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Friend: A friend.
2110 def deserialize_friends( 2111 self, payload: typedefs.JSONObject 2112 ) -> collections.Sequence[friends.Friend]: 2113 mut_seq: typing.MutableSequence[friends.Friend] = [] 2114 if raw_friends := payload.get("friends"): 2115 for friend in raw_friends: 2116 mut_seq.append(self.deserialize_friend(friend)) 2117 return mut_seq
Deserialize a JSON sequence of Bungie friends information.
This is usually used to deserialize the incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of friends.
2119 def deserialize_friend_requests( 2120 self, payload: typedefs.JSONObject 2121 ) -> friends.FriendRequestView: 2122 incoming: typing.MutableSequence[friends.Friend] = [] 2123 outgoing: typing.MutableSequence[friends.Friend] = [] 2124 2125 if raw_incoming_requests := payload.get("incomingRequests"): 2126 for incoming_request in raw_incoming_requests: 2127 incoming.append(self.deserialize_friend(incoming_request)) 2128 2129 if raw_outgoing_requests := payload.get("outgoingRequests"): 2130 for outgoing_request in raw_outgoing_requests: 2131 outgoing.append(self.deserialize_friend(outgoing_request)) 2132 2133 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
Deserialize a JSON sequence of Bungie friend requests information.
This is used for incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.FriendRequestView]: A sequence of incoming and outgoing friends.
2158 def deserialize_fireteams( 2159 self, payload: typedefs.JSONObject 2160 ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]: 2161 fireteams_: typing.MutableSequence[fireteams.Fireteam] = [] 2162 2163 result: list[typedefs.JSONObject] 2164 if not (result := payload["results"]): 2165 return None 2166 for elem in result: 2167 fireteams_.append( 2168 self._set_fireteam_fields( 2169 elem, total_results=int(payload["totalResults"]) 2170 ) 2171 ) 2172 return fireteams_
Deserialize a JSON sequence of Bungie fireteams information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Fireteam]: A sequence of fireteam.
2174 def deserialize_fireteam_destiny_users( 2175 self, payload: typedefs.JSONObject 2176 ) -> fireteams.FireteamUser: 2177 destiny_obj = self.deserialize_destiny_membership(payload) 2178 # We could helpers.just return a DestinyMembership object but this is 2179 # missing the fireteam display name and id fields. 2180 return fireteams.FireteamUser( 2181 net=self._net, 2182 id=destiny_obj.id, 2183 code=destiny_obj.code, 2184 icon=destiny_obj.icon, 2185 types=destiny_obj.types, 2186 type=destiny_obj.type, 2187 is_public=destiny_obj.is_public, 2188 crossave_override=destiny_obj.crossave_override, 2189 name=destiny_obj.name, 2190 last_seen_name=destiny_obj.last_seen_name, 2191 fireteam_display_name=payload["FireteamDisplayName"], 2192 fireteam_membership_id=enums.MembershipType( 2193 payload["FireteamMembershipType"] 2194 ), 2195 )
Deserialize a JSON payload of Bungie fireteam destiny users information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamUser: A fireteam user.
2197 def deserialize_fireteam_members( 2198 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2199 ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]: 2200 members_: list[fireteams.FireteamMember] = [] 2201 if members := payload.get("Members" if not alternatives else "Alternates"): 2202 for member in members: 2203 bungie_fields = self.deserialize_partial_bungie_user(member) 2204 members_fields = fireteams.FireteamMember( 2205 destiny_user=self.deserialize_fireteam_destiny_users(member), 2206 has_microphone=member["hasMicrophone"], 2207 character_id=int(member["characterId"]), 2208 date_joined=time.clean_date(member["dateJoined"]), 2209 last_platform_invite_date=time.clean_date( 2210 member["lastPlatformInviteAttemptDate"] 2211 ), 2212 last_platform_invite_result=int( 2213 member["lastPlatformInviteAttemptResult"] 2214 ), 2215 net=self._net, 2216 name=bungie_fields.name, 2217 id=bungie_fields.id, 2218 icon=bungie_fields.icon, 2219 is_public=bungie_fields.is_public, 2220 crossave_override=bungie_fields.crossave_override, 2221 types=bungie_fields.types, 2222 type=bungie_fields.type, 2223 ) 2224 members_.append(members_fields) 2225 else: 2226 return None 2227 return members_
Deserialize a JSON sequence of Bungie fireteam members information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - alternatives (
bool): If set toTrue, Then it will deserialize thealternativesdata in the payload. If not the it will just deserialize themembersdata.
Returns
typing.Optional[collections.Sequence[aiobungie.crates.FireteamUser]]: An optional sequence of the fireteam members.
2229 def deserialize_available_fireteams( 2230 self, 2231 data: typedefs.JSONObject, 2232 *, 2233 no_results: bool = False, 2234 ) -> typing.Union[ 2235 fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam] 2236 ]: 2237 fireteams_: list[fireteams.AvailableFireteam] = [] 2238 2239 # This needs to be used outside the results 2240 # JSON key. 2241 if no_results is True: 2242 payload = data 2243 2244 if result := payload.get("results"): 2245 2246 for fireteam in result: 2247 found_fireteams = self._set_fireteam_fields(fireteam["Summary"]) 2248 fireteams_fields = fireteams.AvailableFireteam( 2249 id=found_fireteams.id, 2250 group_id=found_fireteams.group_id, 2251 platform=found_fireteams.platform, 2252 activity_type=found_fireteams.activity_type, 2253 is_immediate=found_fireteams.is_immediate, 2254 is_public=found_fireteams.is_public, 2255 is_valid=found_fireteams.is_valid, 2256 owner_id=found_fireteams.owner_id, 2257 player_slot_count=found_fireteams.player_slot_count, 2258 available_player_slots=found_fireteams.available_player_slots, 2259 available_alternate_slots=found_fireteams.available_alternate_slots, 2260 title=found_fireteams.title, 2261 date_created=found_fireteams.date_created, 2262 locale=found_fireteams.locale, 2263 last_modified=found_fireteams.last_modified, 2264 total_results=found_fireteams.total_results, 2265 members=self.deserialize_fireteam_members(payload), 2266 alternatives=self.deserialize_fireteam_members( 2267 payload, alternatives=True 2268 ), 2269 ) 2270 fireteams_.append(fireteams_fields) 2271 if no_results: 2272 return fireteams_fields 2273 return fireteams_
Deserialize a JSON payload of a sequence of/fireteam information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - no_results (
bool): Whether to deserialize the data fromresultsin the payload or not.
Returns
typing.Union[aiobungie.crates.fireteams.AvailableFireteam, collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]]# noqa (E501): An available fireteam or a sequence of available fireteam.
2275 def deserialize_fireteam_party( 2276 self, payload: typedefs.JSONObject 2277 ) -> fireteams.FireteamParty: 2278 last_destination_hash: typing.Optional[int] = None 2279 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2280 last_destination_hash = int(raw_dest_hash) 2281 2282 return fireteams.FireteamParty( 2283 members=[ 2284 self._deserialize_fireteam_party_member(member) 2285 for member in payload["partyMembers"] 2286 ], 2287 activity=self._deserialize_fireteam_party_current_activity( 2288 payload["currentActivity"] 2289 ), 2290 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2291 last_destination_hash=last_destination_hash, 2292 tracking=payload["tracking"], 2293 )
Deserialize a JSON payload of profileTransitory component response.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamParty: A fireteam party object of the current fireteam.
2340 def deserialize_seasonal_artifact( 2341 self, payload: typedefs.JSONObject 2342 ) -> season.Artifact: 2343 if raw_artifact := payload.get("seasonalArtifact"): 2344 if points := raw_artifact.get("pointProgression"): 2345 points_prog = progressions.Progression( 2346 hash=points["progressionHash"], 2347 level=points["level"], 2348 cap=points["levelCap"], 2349 daily_limit=points["dailyLimit"], 2350 weekly_limit=points["weeklyLimit"], 2351 current_progress=points["currentProgress"], 2352 daily_progress=points["dailyProgress"], 2353 needed=points["progressToNextLevel"], 2354 next_level=points["nextLevelAt"], 2355 ) 2356 2357 if bonus := raw_artifact.get("powerBonusProgression"): 2358 power_bonus_prog = progressions.Progression( 2359 hash=bonus["progressionHash"], 2360 level=bonus["level"], 2361 cap=bonus["levelCap"], 2362 daily_limit=bonus["dailyLimit"], 2363 weekly_limit=bonus["weeklyLimit"], 2364 current_progress=bonus["currentProgress"], 2365 daily_progress=bonus["dailyProgress"], 2366 needed=bonus["progressToNextLevel"], 2367 next_level=bonus["nextLevelAt"], 2368 ) 2369 artifact = season.Artifact( 2370 net=self._net, 2371 hash=raw_artifact["artifactHash"], 2372 power_bonus=raw_artifact["powerBonus"], 2373 acquired_points=raw_artifact["pointsAcquired"], 2374 bonus=power_bonus_prog, 2375 points=points_prog, 2376 ) 2377 return artifact
Deserialize a JSON payload of a Destiny 2 seasonal artifact information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Artifact: A seasonal artifact.
2379 def deserialize_profile_progression( 2380 self, payload: typedefs.JSONObject 2381 ) -> profile.ProfileProgression: 2382 return profile.ProfileProgression( 2383 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2384 checklist={ 2385 int(check_id): checklists 2386 for check_id, checklists in payload["data"]["checklists"].items() 2387 }, 2388 )
Deserialize a JSON payload of a profile progression component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ProfileProgression: A profile progression component.
2390 def deserialize_instanced_item( 2391 self, payload: typedefs.JSONObject 2392 ) -> items.ItemInstance: 2393 damage_type_hash: typing.Optional[int] = None 2394 if raw_damagetype_hash := payload.get("damageTypeHash"): 2395 damage_type_hash = int(raw_damagetype_hash) 2396 2397 required_hashes: typing.Optional[collections.Collection[int]] = None 2398 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2399 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2400 2401 breaker_type: typing.Optional[items.ItemBreakerType] = None 2402 if raw_break_type := payload.get("breakerType"): 2403 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2404 2405 breaker_type_hash: typing.Optional[int] = None 2406 if raw_break_type_hash := payload.get("breakerTypeHash"): 2407 breaker_type_hash = int(raw_break_type_hash) 2408 2409 energy: typing.Optional[items.ItemEnergy] = None 2410 if raw_energy := payload.get("energy"): 2411 energy = self.deserialize_item_energy(raw_energy) 2412 2413 primary_stats = None 2414 if raw_primary_stats := payload.get("primaryStat"): 2415 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2416 2417 return items.ItemInstance( 2418 damage_type=enums.DamageType(int(payload["damageType"])), 2419 damage_type_hash=damage_type_hash, 2420 primary_stat=primary_stats, 2421 item_level=int(payload["itemLevel"]), 2422 quality=int(payload["quality"]), 2423 is_equipped=payload["isEquipped"], 2424 can_equip=payload["canEquip"], 2425 equip_required_level=int(payload["equipRequiredLevel"]), 2426 required_equip_unlock_hashes=required_hashes, 2427 cant_equip_reason=int(payload["cannotEquipReason"]), 2428 breaker_type=breaker_type, 2429 breaker_type_hash=breaker_type_hash, 2430 energy=energy, 2431 )
Deserialize a JSON object into an instanced item.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ItemInstance: An instanced item object.
2433 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2434 energy_hash: typing.Optional[int] = None 2435 if raw_energy_hash := payload.get("energyTypeHash"): 2436 energy_hash = int(raw_energy_hash) 2437 2438 return items.ItemEnergy( 2439 hash=energy_hash, 2440 type=items.ItemEnergyType(int(payload["energyType"])), 2441 capacity=int(payload["energyCapacity"]), 2442 used_energy=int(payload["energyUsed"]), 2443 unused_energy=int(payload["energyUnused"]), 2444 )
2446 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2447 perk_hash: typing.Optional[int] = None 2448 if raw_perk_hash := payload.get("perkHash"): 2449 perk_hash = int(raw_perk_hash) 2450 2451 return items.ItemPerk( 2452 hash=perk_hash, 2453 icon=assets.Image(payload["iconPath"]), 2454 is_active=payload["isActive"], 2455 is_visible=payload["visible"], 2456 )
2458 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2459 plug_hash: typing.Optional[int] = None 2460 if raw_plug_hash := payload.get("plugHash"): 2461 plug_hash = int(raw_plug_hash) 2462 2463 enable_fail_indexes: typing.Optional[list[int]] = None 2464 if raw_indexes := payload.get("enableFailIndexes"): 2465 enable_fail_indexes = [int(index) for index in raw_indexes] 2466 2467 return items.ItemSocket( 2468 plug_hash=plug_hash, 2469 is_enabled=payload["isEnabled"], 2470 enable_fail_indexes=enable_fail_indexes, 2471 is_visible=payload.get("visible"), 2472 )
2481 def deserialize_plug_item_state( 2482 self, payload: typedefs.JSONObject 2483 ) -> items.PlugItemState: 2484 item_hash: typing.Optional[int] = None 2485 if raw_item_hash := payload.get("plugItemHash"): 2486 item_hash = int(raw_item_hash) 2487 2488 insert_fail_indexes: typedefs.NoneOr[list[int]] = None 2489 if raw_fail_indexes := payload.get("insertFailIndexes"): 2490 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2491 2492 enable_fail_indexes: typedefs.NoneOr[list[int]] = None 2493 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2494 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2495 2496 return items.PlugItemState( 2497 item_hash=item_hash, 2498 insert_fail_indexes=insert_fail_indexes, 2499 enable_fail_indexes=enable_fail_indexes, 2500 is_enabled=payload["enabled"], 2501 can_insert=payload["canInsert"], 2502 )
68@typing.final 69class FireteamActivity(int, enums.Enum): 70 """An enum for the fireteam activities.""" 71 72 ALL = 0 73 CRUCIBLE = 2 74 TRIALS_OF_OSIRIS = 3 75 NIGHTFALL = 4 76 ANY = 5 77 GAMBIT = 6 78 BLIND_WELL = 7 79 NIGHTMARE_HUNTS = 12 80 ALTARS_OF_SORROWS = 14 81 DUNGEON = 15 82 RAID_LW = 20 83 RAID_GOS = 21 84 RAID_DSC = 22 85 EXO_CHALLENGE = 23 86 S12_WRATHBORN = 24 87 EMPIRE_HUNTS = 25 88 S13_BATTLEGROUNDS = 26 89 EXOTIC_QUEST = 27 90 RAID_VOG = 28 91 S14_EXPUNGE = 30 92 S15_ASTRAL_ALIGNMENT = 31 93 S15_SHATTERED_RELAM = 32 94 SHATTERED_THRONE = 33 95 PROPHECY = 34 96 PIT_OF_HERESY = 35 97 DOE = 36 98 """Dares of Eternity.""" 99 DUNGEON_GOA = 37 100 """Grasp of Avarice.""" 101 VOW_OF_THE_DISCPILE = 38 102 CAMPAIGN = 39 103 WELLSPRING = 40 104 S16_BATTLEGROUNDS = 41 105 S17_NIGHTMARE_CONTAINMENT = 44 106 S17_SEVER = 45
An enum for the fireteam activities.
132@typing.final 133class FireteamDate(int, enums.Enum): 134 """An enum for fireteam date ranges.""" 135 136 ALL = 0 137 NOW = 1 138 TODAY = 2 139 TWO_DAYS = 3 140 THIS_WEEK = 4
An enum for fireteam date ranges.
109@typing.final 110class FireteamLanguage(str, enums.Enum): 111 """An enum for fireteams languages filters.""" 112 113 ALL = "" 114 ENGLISH = "en" 115 FRENCH = "fr" 116 ESPANOL = "es" 117 DEUTSCH = "de" 118 ITALIAN = "it" 119 JAPANESE = "ja" 120 PORTUGUESE = "pt-br" 121 RUSSIAN = "ru" 122 POLISH = "pl" 123 KOREAN = "ko" 124 # ? China 125 ZH_CHT = "zh-cht" 126 ZH_CHS = "zh-chs" 127 128 def __str__(self) -> str: 129 return str(self.value)
An enum for fireteams languages filters.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
55@typing.final 56class FireteamPlatform(int, enums.Enum): 57 """An enum for fireteam related to bungie fireteams. 58 This is different from the normal `aiobungie.MembershipType`. 59 """ 60 61 ANY = 0 62 PSN_NETWORK = 1 63 XBOX_LIVE = 2 64 STEAM = 4 65 STADIA = 5
An enum for fireteam related to bungie fireteams.
This is different from the normal aiobungie.MembershipType.
102class Flag(__enum.Flag): 103 """Builtin Python enum flag with extra handlings.""" 104 105 # Needs to type this here for mypy 106 _value_: int 107 108 @property 109 def name(self) -> str: # type: ignore[override] 110 if self._name_ is None: 111 self._name_ = f"UNKNOWN {self._value_}" 112 113 return self._name_ 114 115 @property 116 def value(self) -> int: # type: ignore[override] 117 return self._value_ 118 119 def __str__(self) -> str: 120 return self.name 121 122 def __repr__(self) -> str: 123 return f"<{type(self).__name__}.{self.name}: {self._value_!s}>" 124 125 def __int__(self) -> int: 126 if isinstance(self.value, _ITERABLE): 127 raise TypeError( 128 f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.", 129 ) 130 return int(self.value) 131 132 def __or__(self, other: typing.Union[Flag, int]) -> Flag: 133 return self.__class__(self._value_ | int(other)) 134 135 def __xor__(self, other: typing.Union[Flag, int]) -> Flag: 136 return self.__class__(self._value_ ^ int(other)) 137 138 def __and__(self, other: typing.Union[Flag, int]) -> Flag: 139 return self.__class__(other & int(other)) 140 141 def __invert__(self) -> Flag: 142 return self.__class__(~self._value_) 143 144 def __contains__(self, other: typing.Union[Flag, int]) -> bool: 145 return self.value & int(other) == int(other)
Builtin Python enum flag with extra handlings.
45class FlatIterator(typing.Generic[Item]): 46 """A Flat, In-Memory iterator for sequenced based data. 47 48 Example 49 ------- 50 ```py 51 iterator = FlatIterator([1, 2, 3]) 52 53 # Map the results. 54 for item in iterator.map(lambda item: item * 2): 55 print(item) 56 # 2 57 # 4 58 59 # Indexing is also supported. 60 print(iterator[0]) 61 # 1 62 63 # Normal iteration. 64 for item in iterator: 65 print(item) 66 # 1 67 # 2 68 # 3 69 70 # Union two iterators. 71 iterator2 = FlatIterator([4, 5, 6]) 72 final = iterator | iterator2 73 # <FlatIterator([1, 2, 3, 4, 5, 6])> 74 ``` 75 76 Parameters 77 ---------- 78 items: `collections.Iterable[Item]` 79 The items to iterate over. 80 """ 81 82 __slots__ = ("_items",) 83 84 def __init__(self, items: collections.Iterable[Item]) -> None: 85 self._items = iter(items) 86 87 @typing.overload 88 def collect(self) -> list[Item]: 89 ... 90 91 @typing.overload 92 def collect(self, casting: _B) -> list[_B]: 93 ... 94 95 def collect( 96 self, casting: typing.Optional[_B] = None 97 ) -> typing.Union[list[Item], list[_B]]: 98 """Collects all items in the iterator into a list and cast them into an object if provided. 99 100 Example 101 ------- 102 >>> iterator = FlatIterator([1, 2, 3]) 103 >>> iterator.collect(casting=str) 104 ["1", "2", "3"] 105 106 Parameters 107 ---------- 108 casting: `T | None` 109 The type to cast the items to. If `None` is provided, the items will be returned as is. 110 111 Raises 112 ------ 113 `StopIteration` 114 If no elements are left in the iterator. 115 """ 116 if casting is not None: 117 return typing.cast(list[_B], list(map(casting, self._items))) 118 119 return list(self._items) 120 121 def next(self) -> Item: 122 """Returns the next item in the iterator. 123 124 Example 125 ------- 126 ```py 127 iterator = FlatIterator(["1", "2", "3"]) 128 item = iterator.next() 129 assert item == "1" 130 item = iterator.next() 131 assert item == "2" 132 ``` 133 134 Raises 135 ------ 136 `StopIteration` 137 If no elements are left in the iterator. 138 """ 139 try: 140 return self.__next__() 141 except StopIteration: 142 self._ok() 143 144 def map( 145 self, predicate: collections.Callable[[Item], OtherItem] 146 ) -> FlatIterator[OtherItem]: 147 """Maps each item in the iterator to its predicated value. 148 149 Example 150 ------- 151 ```py 152 iterator = FlatIterator(["1", "2", "3"]).map(lambda value: int(value)) 153 print(iterator) 154 # <FlatIterator([1, 2, 3])> 155 ``` 156 157 Parameters 158 ---------- 159 predicate: `collections.Callable[[Item], OtherItem]` 160 The function to map each item in the iterator to its predicated value. 161 162 Returns 163 ------- 164 `FlatIterator[OtherItem]` 165 The mapped iterator. 166 167 Raises 168 ------ 169 `StopIteration` 170 If no elements are left in the iterator. 171 """ 172 return FlatIterator(map(predicate, self._items)) 173 174 def take(self, n: int) -> FlatIterator[Item]: 175 """Take the first number of items until the number of items are yielded or 176 the end of the iterator is reached. 177 178 Example 179 ------- 180 ```py 181 iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 182 print(iterator.take(2)) 183 # <FlatIterator([GameMode.RAID, GameMode.STRIKE])> 184 ``` 185 186 Parameters 187 ---------- 188 n: `int` 189 The number of items to take. 190 191 Raises 192 ------ 193 `StopIteration` 194 If no elements are left in the iterator. 195 """ 196 return FlatIterator(itertools.islice(self._items, n)) 197 198 def take_while( 199 self, predicate: collections.Callable[[Item], bool] 200 ) -> FlatIterator[Item]: 201 """Yields items from the iterator while predicate returns `True`. 202 203 Example 204 ------- 205 ```py 206 iterator = FlatIterator([STEAM, XBOX, STADIA]) 207 print(iterator.take_while(lambda platform: platform is not XBOX)) 208 # <FlatIterator([STEAM])> 209 ``` 210 211 Parameters 212 ---------- 213 predicate: `collections.Callable[[Item], bool]` 214 The function to predicate each item in the iterator. 215 216 Raises 217 ------ 218 `StopIteration` 219 If no elements are left in the iterator. 220 """ 221 return FlatIterator(itertools.takewhile(predicate, self._items)) 222 223 def drop_while( 224 self, predicate: collections.Callable[[Item], bool] 225 ) -> FlatIterator[Item]: 226 """Yields items from the iterator while predicate returns `False`. 227 228 Example 229 ------- 230 ```py 231 iterator = FlatIterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]) 232 print(iterator.drop_while(lambda membership: membership.name is not "Jim")) 233 # <FlatIterator([DestinyMembership(name="Bob")])> 234 ``` 235 236 Parameters 237 ---------- 238 predicate: `collections.Callable[[Item], bool]` 239 The function to predicate each item in the iterator. 240 241 Raises 242 ------ 243 `StopIteration` 244 If no elements are left in the iterator. 245 """ 246 return FlatIterator(itertools.dropwhile(predicate, self._items)) 247 248 def filter( 249 self, predicate: collections.Callable[[Item], bool] 250 ) -> FlatIterator[Item]: 251 """Filters the iterator to only yield items that match the predicate. 252 253 Example 254 ------- 255 ```py 256 names = FlatIterator(["Jim", "Bob", "Mike", "Jess"]) 257 print(names.filter(lambda n: n != "Jim")) 258 # <FlatIterator(["Bob", "Mike", "Jess"])> 259 ``` 260 """ 261 return FlatIterator(filter(predicate, self._items)) 262 263 def skip(self, n: int) -> FlatIterator[Item]: 264 """Skips the first number of items in the iterator. 265 266 Example 267 ------- 268 ```py 269 iterator = FlatIterator([STEAM, XBOX, STADIA]) 270 print(iterator.skip(1)) 271 # <FlatIterator([XBOX, STADIA])> 272 ``` 273 """ 274 return FlatIterator(itertools.islice(self._items, n, None)) 275 276 def discard( 277 self, predicate: collections.Callable[[Item], bool] 278 ) -> FlatIterator[Item]: 279 """Discards all elements in the iterator for which the predicate function returns true. 280 281 Example 282 ------- 283 ```py 284 iterator = FlatIterator(['A', 'B', 'C']) 285 print(iterator.discard(lambda x: x == 'B')) 286 # <FlatIterator(['A', 'C'])> 287 ``` 288 289 Parameters 290 ---------- 291 predicate: `collections.Callable[[Item], bool]` 292 The function to test each item in the iterator. 293 294 Raises 295 ------ 296 `StopIteration` 297 If no elements are left in the iterator. 298 """ 299 return FlatIterator(filter(lambda x: not predicate(x), self._items)) 300 301 def zip( 302 self, other: FlatIterator[OtherItem] 303 ) -> FlatIterator[tuple[Item, OtherItem]]: 304 """Zips the iterator with another iterable. 305 306 Example 307 ------- 308 ```py 309 iterator = FlatIterator([1, 3, 5]) 310 other = FlatIterator([2, 4, 6]) 311 for item, other_item in iterator.zip(other): 312 print(item, other_item) 313 # <FlatIterator([(1, 2), (3, 4), (5, 6)])> 314 ``` 315 316 Parameters 317 ---------- 318 other: `FlatIterator[OtherItem]` 319 The iterable to zip with. 320 321 Raises 322 ------ 323 `StopIteration` 324 If no elements are left in the iterator. 325 """ 326 return FlatIterator(zip(self._items, other)) 327 328 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 329 """`True` if all items in the iterator match the predicate. 330 331 Example 332 ------- 333 ```py 334 iterator = FlatIterator([1, 2, 3]) 335 while iterator.all(lambda item: isinstance(item, int)): 336 print("Still all integers") 337 continue 338 # Still all integers 339 ``` 340 341 Parameters 342 ---------- 343 predicate: `collections.Callable[[Item], bool]` 344 The function to test each item in the iterator. 345 346 Raises 347 ------ 348 `StopIteration` 349 If no elements are left in the iterator. 350 """ 351 return all(predicate(item) for item in self) 352 353 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 354 """`True` if any items in the iterator match the predicate. 355 356 Example 357 ------- 358 ```py 359 iterator = FlatIterator([1, 2, 3]) 360 if iterator.any(lambda item: isinstance(item, int)): 361 print("At least one item is an int.") 362 # At least one item is an int. 363 ``` 364 365 Parameters 366 ---------- 367 predicate: `collections.Callable[[Item], bool]` 368 The function to test each item in the iterator. 369 370 Raises 371 ------ 372 `StopIteration` 373 If no elements are left in the iterator. 374 """ 375 return any(predicate(item) for item in self) 376 377 def sort( 378 self, 379 *, 380 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 381 reverse: bool = False, 382 ) -> FlatIterator[Item]: 383 """Sorts the iterator. 384 385 Example 386 ------- 387 ```py 388 iterator = FlatIterator([3, 1, 6, 7]) 389 print(iterator.sort(key=lambda item: item)) 390 # <FlatIterator([1, 3, 6, 7])> 391 ``` 392 393 Parameters 394 ---------- 395 key: `collections.Callable[[Item], Any]` 396 The function to sort by. 397 reverse: `bool` 398 Whether to reverse the sort. 399 400 Raises 401 ------ 402 `StopIteration` 403 If no elements are left in the iterator. 404 """ 405 return FlatIterator(sorted(self._items, key=key, reverse=reverse)) 406 407 def first(self) -> Item: 408 """Returns the first item in the iterator. 409 410 Example 411 ------- 412 ```py 413 iterator = FlatIterator([3, 1, 6, 7]) 414 print(iterator.first()) 415 3 416 ``` 417 418 Raises 419 ------ 420 `StopIteration` 421 If no elements are left in the iterator. 422 """ 423 return self.take(1).next() 424 425 def reversed(self) -> FlatIterator[Item]: 426 """Returns a new iterator that yields the items in the iterator in reverse order. 427 428 Example 429 ------- 430 ```py 431 iterator = FlatIterator([3, 1, 6, 7]) 432 print(iterator.reversed()) 433 # <FlatIterator([7, 6, 1, 3])> 434 ``` 435 436 Raises 437 ------ 438 `StopIteration` 439 If no elements are left in the iterator. 440 """ 441 return FlatIterator(reversed(self.collect())) 442 443 def count(self) -> int: 444 """Returns the number of items in the iterator. 445 446 Example 447 ------- 448 ```py 449 iterator = FlatIterator([3, 1, 6, 7]) 450 print(iterator.count()) 451 4 452 ``` 453 """ 454 count = 0 455 for _ in self: 456 count += 1 457 458 return count 459 460 def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]: 461 """Returns a new iterator that yields all items from both iterators. 462 463 Example 464 ------- 465 ```py 466 iterator = FlatIterator([1, 2, 3]) 467 other = FlatIterator([4, 5, 6]) 468 print(iterator.union(other)) 469 # <FlatIterator([1, 2, 3, 4, 5, 6])> 470 ``` 471 472 Parameters 473 ---------- 474 other: `FlatIterator[Item]` 475 The iterable to union with. 476 477 Raises 478 ------ 479 `StopIteration` 480 If no elements are left in the iterator. 481 """ 482 return FlatIterator(itertools.chain(self._items, other)) 483 484 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 485 """Calls the function on each item in the iterator. 486 487 Example 488 ------- 489 ```py 490 iterator = FlatIterator([1, 2, 3]) 491 iterator.for_each(lambda item: print(item)) 492 # 1 493 # 2 494 # 3 495 ``` 496 497 Parameters 498 ---------- 499 func: `typeshed.Callable[[Item], None]` 500 The function to call on each item in the iterator. 501 """ 502 for item in self: 503 func(item) 504 505 async def async_for_each( 506 self, func: collections.Callable[[Item], collections.Coroutine[None, None, None]] 507 ) -> None: 508 """Calls the async function on each item in the iterator concurrently. 509 510 Example 511 ------- 512 ```py 513 async def signup(username: str) -> None: 514 async with aiohttp.request('POST', '...') as r: 515 # Actual logic. 516 ... 517 518 async def main(): 519 users = aiobungie.into_iter(["user_danny", "user_jojo"]) 520 await users.async_for_each(lambda username: signup(username)) 521 ``` 522 523 Parameters 524 ---------- 525 func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]` 526 The async function to call on each item in the iterator. 527 """ 528 await _helpers.awaits(*(func(item) for item in self)) 529 530 def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]: 531 """Returns a new iterator that yields tuples of the index and item. 532 533 Example 534 ------- 535 ```py 536 iterator = FlatIterator([1, 2, 3]) 537 for index, item in iterator.enumerate(): 538 print(index, item) 539 # 0 1 540 # 1 2 541 # 2 3 542 ``` 543 544 Raises 545 ------ 546 `StopIteration` 547 If no elements are left in the iterator. 548 """ 549 return FlatIterator(enumerate(self._items, start=start)) 550 551 def _ok(self) -> typing.NoReturn: 552 raise StopIteration("No more items in the iterator.") from None 553 554 def __getitem__(self, index: int) -> Item: 555 try: 556 return self.skip(index).first() 557 except IndexError: 558 self._ok() 559 560 def __or__(self, other: FlatIterator[Item]) -> FlatIterator[Item]: 561 return self.union(other) 562 563 # This is a never. 564 def __setitem__(self) -> typing.NoReturn: 565 raise TypeError( 566 f"{type(self).__name__} doesn't support item assignment." 567 ) from None 568 569 def __repr__(self) -> str: 570 return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>' 571 572 def __len__(self) -> int: 573 return self.count() 574 575 def __iter__(self) -> FlatIterator[Item]: 576 return self 577 578 def __next__(self) -> Item: 579 try: 580 item = next(self._items) 581 except StopIteration: 582 self._ok() 583 584 return item
A Flat, In-Memory iterator for sequenced based data.
Example
iterator = FlatIterator([1, 2, 3])
# Map the results.
for item in iterator.map(lambda item: item * 2):
print(item)
# 2
# 4
# Indexing is also supported.
print(iterator[0])
# 1
# Normal iteration.
for item in iterator:
print(item)
# 1
# 2
# 3
# Union two iterators.
iterator2 = FlatIterator([4, 5, 6])
final = iterator | iterator2
# <FlatIterator([1, 2, 3, 4, 5, 6])>
Parameters
- items (
collections.Iterable[Item]): The items to iterate over.
95 def collect( 96 self, casting: typing.Optional[_B] = None 97 ) -> typing.Union[list[Item], list[_B]]: 98 """Collects all items in the iterator into a list and cast them into an object if provided. 99 100 Example 101 ------- 102 >>> iterator = FlatIterator([1, 2, 3]) 103 >>> iterator.collect(casting=str) 104 ["1", "2", "3"] 105 106 Parameters 107 ---------- 108 casting: `T | None` 109 The type to cast the items to. If `None` is provided, the items will be returned as is. 110 111 Raises 112 ------ 113 `StopIteration` 114 If no elements are left in the iterator. 115 """ 116 if casting is not None: 117 return typing.cast(list[_B], list(map(casting, self._items))) 118 119 return list(self._items)
Collects all items in the iterator into a list and cast them into an object if provided.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> iterator.collect(casting=str)
["1", "2", "3"]
Parameters
- casting (
T | None): The type to cast the items to. IfNoneis provided, the items will be returned as is.
Raises
StopIteration: If no elements are left in the iterator.
121 def next(self) -> Item: 122 """Returns the next item in the iterator. 123 124 Example 125 ------- 126 ```py 127 iterator = FlatIterator(["1", "2", "3"]) 128 item = iterator.next() 129 assert item == "1" 130 item = iterator.next() 131 assert item == "2" 132 ``` 133 134 Raises 135 ------ 136 `StopIteration` 137 If no elements are left in the iterator. 138 """ 139 try: 140 return self.__next__() 141 except StopIteration: 142 self._ok()
Returns the next item in the iterator.
Example
iterator = FlatIterator(["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
StopIteration: If no elements are left in the iterator.
144 def map( 145 self, predicate: collections.Callable[[Item], OtherItem] 146 ) -> FlatIterator[OtherItem]: 147 """Maps each item in the iterator to its predicated value. 148 149 Example 150 ------- 151 ```py 152 iterator = FlatIterator(["1", "2", "3"]).map(lambda value: int(value)) 153 print(iterator) 154 # <FlatIterator([1, 2, 3])> 155 ``` 156 157 Parameters 158 ---------- 159 predicate: `collections.Callable[[Item], OtherItem]` 160 The function to map each item in the iterator to its predicated value. 161 162 Returns 163 ------- 164 `FlatIterator[OtherItem]` 165 The mapped iterator. 166 167 Raises 168 ------ 169 `StopIteration` 170 If no elements are left in the iterator. 171 """ 172 return FlatIterator(map(predicate, self._items))
Maps each item in the iterator to its predicated value.
Example
iterator = FlatIterator(["1", "2", "3"]).map(lambda value: int(value))
print(iterator)
# <FlatIterator([1, 2, 3])>
Parameters
- predicate (
collections.Callable[[Item], OtherItem]): The function to map each item in the iterator to its predicated value.
Returns
FlatIterator[OtherItem]: The mapped iterator.
Raises
StopIteration: If no elements are left in the iterator.
174 def take(self, n: int) -> FlatIterator[Item]: 175 """Take the first number of items until the number of items are yielded or 176 the end of the iterator is reached. 177 178 Example 179 ------- 180 ```py 181 iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 182 print(iterator.take(2)) 183 # <FlatIterator([GameMode.RAID, GameMode.STRIKE])> 184 ``` 185 186 Parameters 187 ---------- 188 n: `int` 189 The number of items to take. 190 191 Raises 192 ------ 193 `StopIteration` 194 If no elements are left in the iterator. 195 """ 196 return FlatIterator(itertools.islice(self._items, n))
Take the first number of items until the number of items are yielded or the end of the iterator is reached.
Example
iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
print(iterator.take(2))
# <FlatIterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
- n (
int): The number of items to take.
Raises
StopIteration: If no elements are left in the iterator.
198 def take_while( 199 self, predicate: collections.Callable[[Item], bool] 200 ) -> FlatIterator[Item]: 201 """Yields items from the iterator while predicate returns `True`. 202 203 Example 204 ------- 205 ```py 206 iterator = FlatIterator([STEAM, XBOX, STADIA]) 207 print(iterator.take_while(lambda platform: platform is not XBOX)) 208 # <FlatIterator([STEAM])> 209 ``` 210 211 Parameters 212 ---------- 213 predicate: `collections.Callable[[Item], bool]` 214 The function to predicate each item in the iterator. 215 216 Raises 217 ------ 218 `StopIteration` 219 If no elements are left in the iterator. 220 """ 221 return FlatIterator(itertools.takewhile(predicate, self._items))
Yields items from the iterator while predicate returns True.
Example
iterator = FlatIterator([STEAM, XBOX, STADIA])
print(iterator.take_while(lambda platform: platform is not XBOX))
# <FlatIterator([STEAM])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
223 def drop_while( 224 self, predicate: collections.Callable[[Item], bool] 225 ) -> FlatIterator[Item]: 226 """Yields items from the iterator while predicate returns `False`. 227 228 Example 229 ------- 230 ```py 231 iterator = FlatIterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]) 232 print(iterator.drop_while(lambda membership: membership.name is not "Jim")) 233 # <FlatIterator([DestinyMembership(name="Bob")])> 234 ``` 235 236 Parameters 237 ---------- 238 predicate: `collections.Callable[[Item], bool]` 239 The function to predicate each item in the iterator. 240 241 Raises 242 ------ 243 `StopIteration` 244 If no elements are left in the iterator. 245 """ 246 return FlatIterator(itertools.dropwhile(predicate, self._items))
Yields items from the iterator while predicate returns False.
Example
iterator = FlatIterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
# <FlatIterator([DestinyMembership(name="Bob")])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
248 def filter( 249 self, predicate: collections.Callable[[Item], bool] 250 ) -> FlatIterator[Item]: 251 """Filters the iterator to only yield items that match the predicate. 252 253 Example 254 ------- 255 ```py 256 names = FlatIterator(["Jim", "Bob", "Mike", "Jess"]) 257 print(names.filter(lambda n: n != "Jim")) 258 # <FlatIterator(["Bob", "Mike", "Jess"])> 259 ``` 260 """ 261 return FlatIterator(filter(predicate, self._items))
Filters the iterator to only yield items that match the predicate.
Example
names = FlatIterator(["Jim", "Bob", "Mike", "Jess"])
print(names.filter(lambda n: n != "Jim"))
# <FlatIterator(["Bob", "Mike", "Jess"])>
263 def skip(self, n: int) -> FlatIterator[Item]: 264 """Skips the first number of items in the iterator. 265 266 Example 267 ------- 268 ```py 269 iterator = FlatIterator([STEAM, XBOX, STADIA]) 270 print(iterator.skip(1)) 271 # <FlatIterator([XBOX, STADIA])> 272 ``` 273 """ 274 return FlatIterator(itertools.islice(self._items, n, None))
Skips the first number of items in the iterator.
Example
iterator = FlatIterator([STEAM, XBOX, STADIA])
print(iterator.skip(1))
# <FlatIterator([XBOX, STADIA])>
276 def discard( 277 self, predicate: collections.Callable[[Item], bool] 278 ) -> FlatIterator[Item]: 279 """Discards all elements in the iterator for which the predicate function returns true. 280 281 Example 282 ------- 283 ```py 284 iterator = FlatIterator(['A', 'B', 'C']) 285 print(iterator.discard(lambda x: x == 'B')) 286 # <FlatIterator(['A', 'C'])> 287 ``` 288 289 Parameters 290 ---------- 291 predicate: `collections.Callable[[Item], bool]` 292 The function to test each item in the iterator. 293 294 Raises 295 ------ 296 `StopIteration` 297 If no elements are left in the iterator. 298 """ 299 return FlatIterator(filter(lambda x: not predicate(x), self._items))
Discards all elements in the iterator for which the predicate function returns true.
Example
iterator = FlatIterator(['A', 'B', 'C'])
print(iterator.discard(lambda x: x == 'B'))
# <FlatIterator(['A', 'C'])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
301 def zip( 302 self, other: FlatIterator[OtherItem] 303 ) -> FlatIterator[tuple[Item, OtherItem]]: 304 """Zips the iterator with another iterable. 305 306 Example 307 ------- 308 ```py 309 iterator = FlatIterator([1, 3, 5]) 310 other = FlatIterator([2, 4, 6]) 311 for item, other_item in iterator.zip(other): 312 print(item, other_item) 313 # <FlatIterator([(1, 2), (3, 4), (5, 6)])> 314 ``` 315 316 Parameters 317 ---------- 318 other: `FlatIterator[OtherItem]` 319 The iterable to zip with. 320 321 Raises 322 ------ 323 `StopIteration` 324 If no elements are left in the iterator. 325 """ 326 return FlatIterator(zip(self._items, other))
Zips the iterator with another iterable.
Example
iterator = FlatIterator([1, 3, 5])
other = FlatIterator([2, 4, 6])
for item, other_item in iterator.zip(other):
print(item, other_item)
# <FlatIterator([(1, 2), (3, 4), (5, 6)])>
Parameters
- other (
FlatIterator[OtherItem]): The iterable to zip with.
Raises
StopIteration: If no elements are left in the iterator.
328 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 329 """`True` if all items in the iterator match the predicate. 330 331 Example 332 ------- 333 ```py 334 iterator = FlatIterator([1, 2, 3]) 335 while iterator.all(lambda item: isinstance(item, int)): 336 print("Still all integers") 337 continue 338 # Still all integers 339 ``` 340 341 Parameters 342 ---------- 343 predicate: `collections.Callable[[Item], bool]` 344 The function to test each item in the iterator. 345 346 Raises 347 ------ 348 `StopIteration` 349 If no elements are left in the iterator. 350 """ 351 return all(predicate(item) for item in self)
True if all items in the iterator match the predicate.
Example
iterator = FlatIterator([1, 2, 3])
while iterator.all(lambda item: isinstance(item, int)):
print("Still all integers")
continue
# Still all integers
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
353 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 354 """`True` if any items in the iterator match the predicate. 355 356 Example 357 ------- 358 ```py 359 iterator = FlatIterator([1, 2, 3]) 360 if iterator.any(lambda item: isinstance(item, int)): 361 print("At least one item is an int.") 362 # At least one item is an int. 363 ``` 364 365 Parameters 366 ---------- 367 predicate: `collections.Callable[[Item], bool]` 368 The function to test each item in the iterator. 369 370 Raises 371 ------ 372 `StopIteration` 373 If no elements are left in the iterator. 374 """ 375 return any(predicate(item) for item in self)
True if any items in the iterator match the predicate.
Example
iterator = FlatIterator([1, 2, 3])
if iterator.any(lambda item: isinstance(item, int)):
print("At least one item is an int.")
# At least one item is an int.
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
377 def sort( 378 self, 379 *, 380 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 381 reverse: bool = False, 382 ) -> FlatIterator[Item]: 383 """Sorts the iterator. 384 385 Example 386 ------- 387 ```py 388 iterator = FlatIterator([3, 1, 6, 7]) 389 print(iterator.sort(key=lambda item: item)) 390 # <FlatIterator([1, 3, 6, 7])> 391 ``` 392 393 Parameters 394 ---------- 395 key: `collections.Callable[[Item], Any]` 396 The function to sort by. 397 reverse: `bool` 398 Whether to reverse the sort. 399 400 Raises 401 ------ 402 `StopIteration` 403 If no elements are left in the iterator. 404 """ 405 return FlatIterator(sorted(self._items, key=key, reverse=reverse))
Sorts the iterator.
Example
iterator = FlatIterator([3, 1, 6, 7])
print(iterator.sort(key=lambda item: item))
# <FlatIterator([1, 3, 6, 7])>
Parameters
- key (
collections.Callable[[Item], Any]): The function to sort by. - reverse (
bool): Whether to reverse the sort.
Raises
StopIteration: If no elements are left in the iterator.
407 def first(self) -> Item: 408 """Returns the first item in the iterator. 409 410 Example 411 ------- 412 ```py 413 iterator = FlatIterator([3, 1, 6, 7]) 414 print(iterator.first()) 415 3 416 ``` 417 418 Raises 419 ------ 420 `StopIteration` 421 If no elements are left in the iterator. 422 """ 423 return self.take(1).next()
Returns the first item in the iterator.
Example
iterator = FlatIterator([3, 1, 6, 7])
print(iterator.first())
3
Raises
StopIteration: If no elements are left in the iterator.
425 def reversed(self) -> FlatIterator[Item]: 426 """Returns a new iterator that yields the items in the iterator in reverse order. 427 428 Example 429 ------- 430 ```py 431 iterator = FlatIterator([3, 1, 6, 7]) 432 print(iterator.reversed()) 433 # <FlatIterator([7, 6, 1, 3])> 434 ``` 435 436 Raises 437 ------ 438 `StopIteration` 439 If no elements are left in the iterator. 440 """ 441 return FlatIterator(reversed(self.collect()))
Returns a new iterator that yields the items in the iterator in reverse order.
Example
iterator = FlatIterator([3, 1, 6, 7])
print(iterator.reversed())
# <FlatIterator([7, 6, 1, 3])>
Raises
StopIteration: If no elements are left in the iterator.
443 def count(self) -> int: 444 """Returns the number of items in the iterator. 445 446 Example 447 ------- 448 ```py 449 iterator = FlatIterator([3, 1, 6, 7]) 450 print(iterator.count()) 451 4 452 ``` 453 """ 454 count = 0 455 for _ in self: 456 count += 1 457 458 return count
Returns the number of items in the iterator.
Example
iterator = FlatIterator([3, 1, 6, 7])
print(iterator.count())
4
460 def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]: 461 """Returns a new iterator that yields all items from both iterators. 462 463 Example 464 ------- 465 ```py 466 iterator = FlatIterator([1, 2, 3]) 467 other = FlatIterator([4, 5, 6]) 468 print(iterator.union(other)) 469 # <FlatIterator([1, 2, 3, 4, 5, 6])> 470 ``` 471 472 Parameters 473 ---------- 474 other: `FlatIterator[Item]` 475 The iterable to union with. 476 477 Raises 478 ------ 479 `StopIteration` 480 If no elements are left in the iterator. 481 """ 482 return FlatIterator(itertools.chain(self._items, other))
Returns a new iterator that yields all items from both iterators.
Example
iterator = FlatIterator([1, 2, 3])
other = FlatIterator([4, 5, 6])
print(iterator.union(other))
# <FlatIterator([1, 2, 3, 4, 5, 6])>
Parameters
- other (
FlatIterator[Item]): The iterable to union with.
Raises
StopIteration: If no elements are left in the iterator.
484 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 485 """Calls the function on each item in the iterator. 486 487 Example 488 ------- 489 ```py 490 iterator = FlatIterator([1, 2, 3]) 491 iterator.for_each(lambda item: print(item)) 492 # 1 493 # 2 494 # 3 495 ``` 496 497 Parameters 498 ---------- 499 func: `typeshed.Callable[[Item], None]` 500 The function to call on each item in the iterator. 501 """ 502 for item in self: 503 func(item)
Calls the function on each item in the iterator.
Example
iterator = FlatIterator([1, 2, 3])
iterator.for_each(lambda item: print(item))
# 1
# 2
# 3
Parameters
- func (
typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
505 async def async_for_each( 506 self, func: collections.Callable[[Item], collections.Coroutine[None, None, None]] 507 ) -> None: 508 """Calls the async function on each item in the iterator concurrently. 509 510 Example 511 ------- 512 ```py 513 async def signup(username: str) -> None: 514 async with aiohttp.request('POST', '...') as r: 515 # Actual logic. 516 ... 517 518 async def main(): 519 users = aiobungie.into_iter(["user_danny", "user_jojo"]) 520 await users.async_for_each(lambda username: signup(username)) 521 ``` 522 523 Parameters 524 ---------- 525 func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]` 526 The async function to call on each item in the iterator. 527 """ 528 await _helpers.awaits(*(func(item) for item in self))
Calls the async function on each item in the iterator concurrently.
Example
async def signup(username: str) -> None:
async with aiohttp.request('POST', '...') as r:
# Actual logic.
...
async def main():
users = aiobungie.into_iter(["user_danny", "user_jojo"])
await users.async_for_each(lambda username: signup(username))
Parameters
- func (
collections.Callable[[Item], collections.Coroutine[None, None, None]]): The async function to call on each item in the iterator.
530 def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]: 531 """Returns a new iterator that yields tuples of the index and item. 532 533 Example 534 ------- 535 ```py 536 iterator = FlatIterator([1, 2, 3]) 537 for index, item in iterator.enumerate(): 538 print(index, item) 539 # 0 1 540 # 1 2 541 # 2 3 542 ``` 543 544 Raises 545 ------ 546 `StopIteration` 547 If no elements are left in the iterator. 548 """ 549 return FlatIterator(enumerate(self._items, start=start))
Returns a new iterator that yields tuples of the index and item.
Example
iterator = FlatIterator([1, 2, 3])
for index, item in iterator.enumerate():
print(index, item)
# 0 1
# 1 2
# 2 3
Raises
StopIteration: If no elements are left in the iterator.
120@attrs.define(auto_exc=True) 121class Forbidden(HTTPException): 122 """Exception that's raised for when status code 403 occurs.""" 123 124 http_status: http.HTTPStatus = attrs.field( 125 default=http.HTTPStatus.FORBIDDEN, init=False 126 )
Exception that's raised for when status code 403 occurs.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class Forbidden.
Inherited Members
- builtins.BaseException
- with_traceback
- args
274@typing.final 275class GameMode(int, Enum): 276 """An Enum for all available gamemodes in Destiny 2.""" 277 278 NONE = 0 279 STORY = 2 280 STRIKE = 3 281 RAID = 4 282 ALLPVP = 5 283 PATROL = 6 284 ALLPVE = 7 285 RESERVED9 = 9 286 CONTROL = 10 287 RESERVED11 = 11 288 CLASH = 12 289 RESERVED13 = 13 290 CRIMSONDOUBLES = 15 291 NIGHTFALL = 16 292 HEROICNIGHTFALL = 17 293 ALLSTRIKES = 18 294 IRONBANNER = 19 295 RESERVED20 = 20 296 RESERVED21 = 21 297 RESERVED22 = 22 298 RESERVED24 = 24 299 ALLMAYHEM = 25 300 RESERVED26 = 26 301 RESERVED27 = 27 302 RESERVED28 = 28 303 RESERVED29 = 29 304 RESERVED30 = 30 305 SUPREMACY = 31 306 PRIVATEMATCHESALL = 32 307 SURVIVAL = 37 308 COUNTDOWN = 38 309 TRIALSOFTHENINE = 39 310 SOCIAL = 40 311 TRIALSCOUNTDOWN = 41 312 TRIALSSURVIVAL = 42 313 IRONBANNERCONTROL = 43 314 IRONBANNERCLASH = 44 315 IRONBANNERSUPREMACY = 45 316 SCOREDNIGHTFALL = 46 317 SCOREDHEROICNIGHTFALL = 47 318 RUMBLE = 48 319 ALLDOUBLES = 49 320 DOUBLES = 50 321 PRIVATEMATCHESCLASH = 51 322 PRIVATEMATCHESCONTROL = 52 323 PRIVATEMATCHESSUPREMACY = 53 324 PRIVATEMATCHESCOUNTDOWN = 54 325 PRIVATEMATCHESSURVIVAL = 55 326 PRIVATEMATCHESMAYHEM = 56 327 PRIVATEMATCHESRUMBLE = 57 328 HEROICADVENTURE = 58 329 SHOWDOWN = 59 330 LOCKDOWN = 60 331 SCORCHED = 61 332 SCORCHEDTEAM = 62 333 GAMBIT = 63 334 ALLPVECOMPETITIVE = 64 335 BREAKTHROUGH = 65 336 BLACKARMORYRUN = 66 337 SALVAGE = 67 338 IRONBANNERSALVAGE = 68 339 PVPCOMPETITIVE = 69 340 PVPQUICKPLAY = 70 341 CLASHQUICKPLAY = 71 342 CLASHCOMPETITIVE = 72 343 CONTROLQUICKPLAY = 73 344 CONTROLCOMPETITIVE = 74 345 GAMBITPRIME = 75 346 RECKONING = 76 347 MENAGERIE = 77 348 VEXOFFENSIVE = 78 349 NIGHTMAREHUNT = 79 350 ELIMINATION = 80 351 MOMENTUM = 81 352 DUNGEON = 82 353 SUNDIAL = 83 354 TRIALS_OF_OSIRIS = 84 355 DARES = 85 356 OFFENSIVE = 86 357 LOSTSECTOR = 87 358 RIFT = 88 359 ZONECONTROL = 89 360 IRONBANNERRIFT = 90
An Enum for all available gamemodes in Destiny 2.
58@typing.final 59class GatingScope(int, enums.Enum): 60 """An enum represents restrictive type of gating that is being performed by an entity. 61 62 This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity 63 applies to everyone equally, or to their specific Profile or Character states. 64 """ 65 66 NONE = 0 67 GLOBAL = 1 68 CLAN = 2 69 PROFILE = 3 70 CHARACTER = 4 71 ITEM = 5 72 ASSUMED_WORST_CASE = 6
An enum represents restrictive type of gating that is being performed by an entity.
This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.
487@typing.final 488class Gender(int, Enum): 489 """An Enum for Destiny Genders.""" 490 491 MALE = 0 492 FEMALE = 1 493 UNKNOWN = 2
An Enum for Destiny Genders.
656@typing.final 657class GroupType(int, Enum): 658 """An enums for the known bungie group types.""" 659 660 GENERAL = 0 661 CLAN = 1
An enums for the known bungie group types.
62@attrs.define(auto_exc=True) 63class HTTPError(AiobungieError): 64 """Exception base used for HTTP request errors.""" 65 66 message: str 67 """The error message.""" 68 69 http_status: http.HTTPStatus 70 """The response status."""
Exception base used for HTTP request errors.
2def __init__(self, message, http_status): 3 self.message = message 4 self.http_status = http_status 5 BaseException.__init__(self, self.message,self.http_status)
Method generated by attrs for class HTTPError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
73@attrs.define(auto_exc=True, kw_only=True) 74class HTTPException(HTTPError): 75 """Exception base internally used for an HTTP request response errors.""" 76 77 error_code: int 78 """The returned Bungie error status code.""" 79 80 http_status: http.HTTPStatus 81 """The request response http status.""" 82 83 throttle_seconds: int 84 """The Bungie response throttle seconds.""" 85 86 url: typing.Optional[typedefs.StrOrURL] 87 """The URL/endpoint caused this error.""" 88 89 body: typing.Any 90 """The response body.""" 91 92 headers: multidict.CIMultiDictProxy[str] 93 """The response headers.""" 94 95 message: str 96 """A Bungie human readable message describes the cause of the error.""" 97 98 error_status: str 99 """A Bungie short error status describes the cause of the error.""" 100 101 message_data: dict[str, str] 102 """A dict of string key, value that includes each cause of the error 103 to a message describes information about that error. 104 """ 105 106 def __str__(self) -> str: 107 if self.message: 108 message_body = self.message 109 110 if self.error_status: 111 error_status_body = self.error_status 112 113 return ( 114 f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: " 115 f"Error status: {error_status_body}, Error message: {message_body} from {self.url} " 116 f"{str(self.body)}" 117 )
Exception base internally used for an HTTP request response errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class HTTPException.
A dict of string key, value that includes each cause of the error to a message describes information about that error.
Inherited Members
- builtins.BaseException
- with_traceback
- args
72class Image: 73 """Representation of an image/avatar/picture at Bungie. 74 75 Example 76 ------- 77 ```py 78 from aiobungie import Image 79 img = Image("img/destiny_content/pgcr/raid_eclipse.jpg") 80 print(img) 81 # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg 82 83 # Stream the image. 84 async for chunk in img: 85 # Byte chunks of the image. 86 print(chunk) 87 88 # Save the image to a file. 89 await img.save("file_name", "/my/path/to/save/to", "jpeg") 90 ``` 91 92 Parameters 93 ---------- 94 path : `str | None` 95 The path to the image. If `None`, the default missing image path will be used. 96 """ 97 98 __slots__ = ("_path",) 99 100 def __init__(self, path: typing.Optional[str] = None) -> None: 101 self._path = path 102 103 @property 104 def is_missing(self) -> bool: 105 return not self._path 106 107 @property 108 def url(self) -> str: 109 """The URL to the image.""" 110 return self.create_url() 111 112 @staticmethod 113 def missing_path() -> str: 114 """Returns the path to the missing Bungie image.""" 115 return "img/misc/missing_icon_d2.png" 116 117 def create_url(self) -> str: 118 """Creates a full URL to the image path. 119 120 Returns 121 ------- 122 str 123 The URL to the image. 124 """ 125 return f"{url.BASE}/{self._path if self._path else self.missing_path()}" 126 127 async def save( 128 self, 129 file_name: str, 130 path: typing.Union[pathlib.Path, str], 131 /, 132 mime_type: typing.Optional[typing.Union[MimeType, str]] = None, 133 ) -> None: 134 """Saves the image to a file. 135 136 Parameters 137 ---------- 138 file_name : `str` 139 A name for the file to save the image to. 140 path : `pathlib.Path | str` 141 A path tp save the image to. 142 143 Other Parameters 144 ---------------- 145 mime_type : `MimeType | str` 146 Optional MIME type of the image. 147 148 Raises 149 ------ 150 `FileNotFoundError` 151 If the path provided does not exist. 152 `RuntimeError` 153 If the image could not be saved. 154 `PermissionError` 155 If the path provided is not writable or does not have write permissions. 156 """ 157 if isinstance(path, pathlib.Path) and not path.exists(): 158 raise FileNotFoundError(f"File does not exist: {path!r}") 159 160 if self.is_missing: 161 return 162 163 mimetype = mime_type or MimeType.PNG 164 path = pathlib.Path(path) 165 166 loop = helpers.get_or_make_loop() 167 pool = concurrent.futures.ThreadPoolExecutor() 168 169 try: 170 with pool: 171 await loop.run_in_executor( 172 pool, _write, path, file_name, mimetype, await self.read() 173 ) 174 _LOGGER.info("Saved image to %s", file_name) 175 176 except asyncio.CancelledError: 177 pass 178 179 except Exception as err: 180 raise RuntimeError("Encountered an error while saving image.") from err 181 182 async def read(self) -> bytes: 183 """Read this image bytes. 184 185 Returns 186 ------- 187 `bytes` 188 The bytes of this image. 189 """ 190 client_session = aiohttp.ClientSession() 191 192 try: 193 await client_session.__aenter__() 194 response = await client_session.get(self.create_url()) 195 196 if 300 >= response.status >= 200: 197 reader = await response.read() 198 199 except Exception as exc: 200 raise RuntimeError(f"Failed to read image: {exc}") from None 201 finally: 202 await client_session.__aexit__(None, None, None) 203 return reader 204 205 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 206 """Iterates over the image bytes lazily. 207 208 Example 209 ------- 210 import aiobungie 211 212 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 213 async for chunk in resource.iter(): 214 print(chunk) 215 216 Returns 217 ------- 218 `collections.AsyncGenerator[bytes, None]` 219 An async generator of the image bytes. 220 """ 221 222 async for chunk in self: 223 yield chunk 224 225 def __repr__(self) -> str: 226 return f"Image(url={self.create_url()})" 227 228 def __str__(self) -> str: 229 return self.create_url() 230 231 def __aiter__(self) -> Image: 232 return self 233 234 async def __anext__(self) -> bytes: 235 return await self.read() 236 237 def __await__(self) -> collections.Generator[None, None, bytes]: 238 return self.__anext__().__await__()
Representation of an image/avatar/picture at Bungie.
Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
# Stream the image.
async for chunk in img:
# Byte chunks of the image.
print(chunk)
# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
- path (
str | None): The path to the image. IfNone, the default missing image path will be used.
112 @staticmethod 113 def missing_path() -> str: 114 """Returns the path to the missing Bungie image.""" 115 return "img/misc/missing_icon_d2.png"
Returns the path to the missing Bungie image.
117 def create_url(self) -> str: 118 """Creates a full URL to the image path. 119 120 Returns 121 ------- 122 str 123 The URL to the image. 124 """ 125 return f"{url.BASE}/{self._path if self._path else self.missing_path()}"
Creates a full URL to the image path.
Returns
- str: The URL to the image.
127 async def save( 128 self, 129 file_name: str, 130 path: typing.Union[pathlib.Path, str], 131 /, 132 mime_type: typing.Optional[typing.Union[MimeType, str]] = None, 133 ) -> None: 134 """Saves the image to a file. 135 136 Parameters 137 ---------- 138 file_name : `str` 139 A name for the file to save the image to. 140 path : `pathlib.Path | str` 141 A path tp save the image to. 142 143 Other Parameters 144 ---------------- 145 mime_type : `MimeType | str` 146 Optional MIME type of the image. 147 148 Raises 149 ------ 150 `FileNotFoundError` 151 If the path provided does not exist. 152 `RuntimeError` 153 If the image could not be saved. 154 `PermissionError` 155 If the path provided is not writable or does not have write permissions. 156 """ 157 if isinstance(path, pathlib.Path) and not path.exists(): 158 raise FileNotFoundError(f"File does not exist: {path!r}") 159 160 if self.is_missing: 161 return 162 163 mimetype = mime_type or MimeType.PNG 164 path = pathlib.Path(path) 165 166 loop = helpers.get_or_make_loop() 167 pool = concurrent.futures.ThreadPoolExecutor() 168 169 try: 170 with pool: 171 await loop.run_in_executor( 172 pool, _write, path, file_name, mimetype, await self.read() 173 ) 174 _LOGGER.info("Saved image to %s", file_name) 175 176 except asyncio.CancelledError: 177 pass 178 179 except Exception as err: 180 raise RuntimeError("Encountered an error while saving image.") from err
Saves the image to a file.
Parameters
- file_name (
str): A name for the file to save the image to. - path (
pathlib.Path | str): A path tp save the image to.
Other Parameters
- mime_type (
MimeType | str): Optional MIME type of the image.
Raises
FileNotFoundError: If the path provided does not exist.RuntimeError: If the image could not be saved.PermissionError: If the path provided is not writable or does not have write permissions.
182 async def read(self) -> bytes: 183 """Read this image bytes. 184 185 Returns 186 ------- 187 `bytes` 188 The bytes of this image. 189 """ 190 client_session = aiohttp.ClientSession() 191 192 try: 193 await client_session.__aenter__() 194 response = await client_session.get(self.create_url()) 195 196 if 300 >= response.status >= 200: 197 reader = await response.read() 198 199 except Exception as exc: 200 raise RuntimeError(f"Failed to read image: {exc}") from None 201 finally: 202 await client_session.__aexit__(None, None, None) 203 return reader
Read this image bytes.
Returns
bytes: The bytes of this image.
205 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 206 """Iterates over the image bytes lazily. 207 208 Example 209 ------- 210 import aiobungie 211 212 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 213 async for chunk in resource.iter(): 214 print(chunk) 215 216 Returns 217 ------- 218 `collections.AsyncGenerator[bytes, None]` 219 An async generator of the image bytes. 220 """ 221 222 async for chunk in self: 223 yield chunk
Iterates over the image bytes lazily.
Example
import aiobungie
resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)
Returns
collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
190@attrs.define(auto_exc=True) 191class InternalServerError(HTTPException): 192 """Raised for 5xx internal server errors."""
Raised for 5xx internal server errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class InternalServerError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
- args
722@typing.final 723class ItemBindStatus(int, Enum): 724 """An enum for Destiny 2 items bind status.""" 725 726 NOT_BOUND = 0 727 BOUND_TO_CHARACTER = 1 728 BOUND_TO_ACCOUNT = 2 729 BOUNT_TO_GUILD = 3
An enum for Destiny 2 items bind status.
732@typing.final 733class ItemLocation(int, Enum): 734 """An enum for Destiny 2 items location.""" 735 736 UNKNOWN = 0 737 INVENTORY = 1 738 VAULT = 2 739 VENDOR = 3 740 POSTMASTER = 4
An enum for Destiny 2 items location.
757@typing.final 758class ItemState(Flag): 759 """An enum for Destiny 2 item states.""" 760 761 NONE = 0 762 LOCKED = 1 763 TRACKED = 2 764 MASTERWORKED = 4 765 CRAFTED = 8 766 """If this bit is set, the item has been 'crafted' by the player.""" 767 HIGHLITED_OBJECTIVE = 16 768 """If this bit is set, the item is a 'highlighted' objective."""
An enum for Destiny 2 item states.
If this bit is set, the item is a 'highlighted' objective.
589@typing.final 590class ItemSubType(int, Enum): 591 """An enum for Destiny 2 inventory items subtype.""" 592 593 NONE = 0 594 AUTORIFLE = 6 595 SHOTGUN = 7 596 MACHINEGUN = 8 597 HANDCANNON = 9 598 ROCKETLAUNCHER = 10 599 FUSIONRIFLE = 11 600 SNIPERRIFLE = 12 601 PULSERIFLE = 13 602 SCOUTRIFLE = 14 603 SIDEARM = 17 604 SWORD = 18 605 MASK = 19 606 SHADER = 20 607 ORNAMENT = 21 608 FUSIONRIFLELINE = 22 609 GRENADELAUNCHER = 23 610 SUBMACHINEGUN = 24 611 TRACERIFLE = 25 612 HELMETARMOR = 26 613 GAUNTLETSARMOR = 27 614 CHESTARMOR = 28 615 LEGARMOR = 29 616 CLASSARMOR = 30 617 BOW = 31 618 DUMMYREPEATABLEBOUNTY = 32
An enum for Destiny 2 inventory items subtype.
621@typing.final 622class ItemTier(int, Enum): 623 """An enum for a Destiny 2 item tier.""" 624 625 NONE = 0 626 BASIC = 3340296461 627 COMMON = 2395677314 628 RARE = 2127292149 629 LEGENDERY = 4008398120 630 EXOTIC = 2759499571
An enum for a Destiny 2 item tier.
556@typing.final 557class ItemType(int, Enum): 558 """Enums for Destiny2's item types.""" 559 560 NONE = 0 561 CURRENCY = 1 562 ARMOR = 2 563 WEAPON = 3 564 MESSAGE = 7 565 ENGRAM = 8 566 CONSUMABLE = 9 567 EXCHANGEMATERIAL = 10 568 MISSIONREWARD = 11 569 QUESTSTEP = 12 570 QUESTSTEPCOMPLETE = 13 571 EMBLEM = 14 572 QUEST = 15 573 SUBCLASS = 16 574 CLANBANNER = 17 575 AURA = 18 576 MOD = 19 577 DUMMY = 20 578 SHIP = 21 579 VEHICLE = 22 580 EMOTE = 23 581 GHOST = 24 582 PACKAGE = 25 583 BOUNTY = 26 584 WRAPPER = 27 585 SEASONALARTIFACT = 28 586 FINISHER = 29
Enums for Destiny2's item types.
713@typing.final 714class MembershipOption(int, Enum): 715 """A enum for GroupV2 membership options.""" 716 717 REVIEWD = 0 718 OPEN = 1 719 CLOSED = 2
A enum for GroupV2 membership options.
463@typing.final 464class MembershipType(int, Enum): 465 """An Enum for Bungie membership types.""" 466 467 NONE = 0 468 XBOX = 1 469 PSN = 2 470 STEAM = 3 471 BLIZZARD = 4 472 STADIA = 5 473 BUNGIE = 254 474 ALL = -1
An Enum for Bungie membership types.
163@attrs.define(auto_exc=True) 164class MembershipTypeError(BadRequest): 165 """A bad request error raised when passing wrong membership to the request. 166 167 Those fields are useful since it returns the correct membership and id which can be used 168 to make the request again with those fields. 169 """ 170 171 membership_type: str = attrs.field(default="") 172 """The errored membership type passed to the request.""" 173 174 membership_id: int = attrs.field(default=0) 175 """The errored user's membership id.""" 176 177 required_membership: str = attrs.field(default="") 178 """The required correct membership for errored user.""" 179 180 def __str__(self) -> str: 181 return ( 182 f"Expected membership: {self.required_membership}, " 183 f"But got {self.membership_type} for id {self.membership_id}" 184 ) 185 186 def __int__(self) -> int: 187 return int(self.membership_id)
A bad request error raised when passing wrong membership to the request.
Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.
2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default, membership_type=attr_dict['membership_type'].default, membership_id=attr_dict['membership_id'].default, required_membership=attr_dict['required_membership'].default): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = http_status 8 self.membership_type = membership_type 9 self.membership_id = membership_id 10 self.required_membership = required_membership 11 BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status,self.membership_type,self.membership_id,self.required_membership)
Method generated by attrs for class MembershipTypeError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
506@typing.final 507class MilestoneType(int, Enum): 508 """An Enum for Destiny 2 milestone types.""" 509 510 UNKNOWN = 0 511 TUTORIAL = 1 512 ONETIME = 2 513 WEEKLY = 3 514 DAILY = 4 515 SPECIAL = 5
An Enum for Destiny 2 milestone types.
129@attrs.define(auto_exc=True) 130class NotFound(HTTPException): 131 """Raised when an unknown request was not found.""" 132 133 http_status: http.HTTPStatus = attrs.field( 134 default=http.HTTPStatus.NOT_FOUND, init=False 135 )
Raised when an unknown request was not found.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class NotFound.
Inherited Members
- builtins.BaseException
- with_traceback
- args
94@typing.final 95class ObjectiveUIStyle(int, enums.Enum): 96 NONE = 0 97 HIGHLIGHTED = 1 98 CRAFTING_WEAPON_LEVEL = 2 99 CRAFTING_WEAPON_LEVEL_PROGRESS = 3 100 CRAFTING_WEAPON_TIMESTAMP = 4 101 CRAFTING_MEMENTOS = 5 102 CRAFTING_MEMENTO_TITLE = 6
An enumeration.
235@typing.final 236class Place(int, Enum): 237 """An Enum for Destiny 2 Places and NOT Planets""" 238 239 ORBIT = 2961497387 240 SOCIAL = 4151112093 241 LIGHT_HOUSE = 4276116472 242 EXPLORE = 3497767639
An Enum for Destiny 2 Places and NOT Planets
200@typing.final 201class Planet(int, Enum): 202 """An Enum for all available planets in Destiny 2.""" 203 204 UNKNOWN = 0 205 """Unknown space""" 206 207 EARTH = 3747705955 208 """Earth""" 209 210 DREAMING_CITY = 2877881518 211 """The Dreaming city.""" 212 213 NESSUS = 3526908984 214 """Nessus""" 215 216 MOON = 3325508439 217 """The Moon""" 218 219 COSMODROME = 3990611421 220 """The Cosmodrome""" 221 222 TANGLED_SHORE = 3821439926 223 """The Tangled Shore""" 224 225 VENUS = 3871070152 226 """Venus""" 227 228 EAZ = 541863059 # Exclusive event. 229 """European Aerial Zone""" 230 231 EUROPA = 1729879943 232 """Europa"""
An Enum for all available planets in Destiny 2.
683@typing.final 684class Presence(int, Enum): 685 """An enum for a bungie friend status.""" 686 687 OFFLINE_OR_UNKNOWN = 0 688 ONLINE = 1
An enum for a bungie friend status.
771@typing.final 772class PrivacySetting(int, Enum): 773 """An enum for players's privacy settings.""" 774 775 OPEN = 0 776 CLAN_AND_FRIENDS = 1 777 FRIENDS_ONLY = 2 778 INVITE_ONLY = 3 779 CLOSED = 4
An enum for players's privacy settings.
352class RESTClient(interfaces.RESTInterface): 353 """A RESTful client implementation for Bungie's API. 354 355 This client is designed to only make HTTP requests and return JSON objects 356 to provide RESTful functionality. 357 358 This client is also used within `aiobungie.Client` which deserialize those returned JSON objects 359 using the factory into Pythonic data classes objects which provide Python functionality. 360 361 Example 362 ------- 363 ```py 364 import aiobungie 365 366 async def main(): 367 async with aiobungie.RESTClient("TOKEN") as rest_client: 368 req = await rest_client.fetch_clan_members(4389205) 369 clan_members = req['results'] 370 for member in clan_members: 371 for k, v in member['destinyUserInfo'].items(): 372 print(k, v) 373 ``` 374 375 Parameters 376 ---------- 377 token : `str` 378 A valid application token from Bungie's developer portal. 379 380 Other Parameters 381 ---------------- 382 max_retries : `int` 383 The max retries number to retry if the request hit a `5xx` status code. 384 max_ratelimit_retries : `int` 385 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 386 client_secret : `typing.Optional[str]` 387 An optional application client secret, 388 This is only needed if you're fetching OAuth2 tokens with this client. 389 client_id : `typing.Optional[int]` 390 An optional application client id, 391 This is only needed if you're fetching OAuth2 tokens with this client. 392 enable_debugging : `bool | str` 393 Whether to enable logging responses or not. 394 395 Logging Levels 396 -------------- 397 * `False`: This will disable logging. 398 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 399 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 400 """ 401 402 __slots__ = ( 403 "_token", 404 "_session", 405 "_lock", 406 "_max_retries", 407 "_client_secret", 408 "_client_id", 409 "_metadata", 410 "_max_rate_limit_retries", 411 ) 412 413 def __init__( 414 self, 415 token: str, 416 /, 417 client_secret: typing.Optional[str] = None, 418 client_id: typing.Optional[int] = None, 419 *, 420 max_retries: int = 4, 421 max_ratelimit_retries: int = 3, 422 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 423 ) -> None: 424 self._session: typing.Optional[_Session] = None 425 self._lock: typing.Optional[asyncio.Lock] = None 426 self._client_secret = client_secret 427 self._client_id = client_id 428 self._token: str = token 429 self._max_retries = max_retries 430 self._max_rate_limit_retries = max_ratelimit_retries 431 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 432 433 self._set_debug_level(enable_debugging) 434 435 @property 436 def client_id(self) -> typing.Optional[int]: 437 return self._client_id 438 439 @property 440 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 441 return self._metadata 442 443 @property 444 def is_alive(self) -> bool: 445 return self._session is not None 446 447 @typing.final 448 async def close(self) -> None: 449 if self._session is not None: 450 await self._session.close() 451 self._session = None 452 453 @typing.final 454 def enable_debugging( 455 self, 456 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 457 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 458 /, 459 ) -> None: 460 self._set_debug_level(level, file) 461 462 @typing.final 463 async def static_request( 464 self, 465 method: typing.Union[RequestMethod, str], 466 path: str, 467 *, 468 auth: typing.Optional[str] = None, 469 json: typing.Optional[dict[str, typing.Any]] = None, 470 ) -> ResponseSig: 471 return await self._request(method, path, auth=auth, json=json) 472 473 @typing.final 474 def build_oauth2_url( 475 self, client_id: typing.Optional[int] = None 476 ) -> typing.Optional[str]: 477 client_id = client_id or self._client_id 478 if client_id is None: 479 return None 480 481 return url.OAUTH2_EP_BUILDER.format( 482 oauth_endpoint=url.OAUTH_EP, 483 client_id=client_id, 484 uuid=_uuid(), 485 ) 486 487 def _open(self) -> _Session: 488 """Open a new client session. This is called internally with contextmanager usage.""" 489 asyncio.get_running_loop() 490 if self._session is None: 491 self._session = _Session.create( 492 owner=False, 493 raise_status=False, 494 connect=None, 495 socket_read=None, 496 socket_connect=None, 497 ) 498 return self._session 499 500 @staticmethod 501 def _set_debug_level( 502 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 503 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 504 ) -> None: 505 506 file_handler = logging.FileHandler(file, mode="w") if file else None 507 if level == "TRACE" or level == TRACE: 508 logging.basicConfig( 509 level=TRACE, handlers=[file_handler] if file_handler else None 510 ) 511 512 elif level: 513 logging.basicConfig( 514 level=logging.DEBUG, handlers=[file_handler] if file_handler else None 515 ) 516 517 async def _request( 518 self, 519 method: typing.Union[RequestMethod, str], 520 route: str, 521 *, 522 base: bool = False, 523 oauth2: bool = False, 524 auth: typing.Optional[str] = None, 525 unwrapping: typing.Literal["json", "read"] = "json", 526 json: typing.Optional[dict[str, typing.Any]] = None, 527 headers: typing.Optional[dict[str, typing.Any]] = None, 528 data: typing.Optional[typing.Union[str, dict[str, typing.Any]]] = None, 529 ) -> ResponseSig: 530 531 retries: int = 0 532 session = self._open() 533 headers = headers or {} 534 535 headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT) 536 headers["X-API-KEY"] = self._token 537 538 if auth is not None: 539 headers[_AUTH_HEADER] = f"Bearer {auth}" 540 541 # Handling endpoints 542 endpoint = url.BASE 543 544 if not base: 545 endpoint = endpoint + url.REST_EP 546 547 if oauth2: 548 headers["Content-Type"] = "application/x-www-form-urlencoded" 549 endpoint = endpoint + url.TOKEN_EP 550 551 if self._lock is None: 552 self._lock = asyncio.Lock() 553 554 while True: 555 try: 556 async with (stack := contextlib.AsyncExitStack()): 557 await stack.enter_async_context(self._lock) 558 559 # We make the request here. 560 taken_time = time.monotonic() 561 response = await stack.enter_async_context( 562 session.client_session.request( 563 method=method, 564 url=f"{endpoint}/{route}", 565 json=json, 566 headers=headers, 567 data=data, 568 ) 569 ) 570 response_time = (time.monotonic() - taken_time) * 1_000 571 572 _LOG.debug( 573 "%s %s %s Time %.4fms", 574 method, 575 f"{endpoint}/{route}", 576 f"{response.status} {response.reason}", 577 response_time, 578 ) 579 580 await self._handle_ratelimit( 581 response, method, route, self._max_rate_limit_retries 582 ) 583 584 if response.status == http.HTTPStatus.NO_CONTENT: 585 return None 586 587 if 300 > response.status >= 200: 588 if unwrapping == "read": 589 # We need to read the bytes for the manifest response. 590 return await response.read() 591 592 if response.content_type == _APP_JSON: 593 json_data = await response.json() 594 595 _LOG.debug( 596 "%s %s %s Time %.4fms", 597 method, 598 f"{endpoint}/{route}", 599 f"{response.status} {response.reason}", 600 response_time, 601 ) 602 603 if _LOG.isEnabledFor(TRACE): 604 headers.update(response.headers) 605 606 _LOG.log( 607 TRACE, 608 "%s", 609 error.stringify_http_message(headers), 610 ) 611 612 # Return the response. 613 # oauth2 responses are not packed inside a Response object. 614 if oauth2: 615 return json_data # type: ignore[no-any-return] 616 617 return json_data["Response"] # type: ignore[no-any-return] 618 619 if ( 620 response.status in _RETRY_5XX 621 and retries < self._max_retries # noqa: W503 622 ): 623 backoff_ = backoff.ExponentialBackOff(maximum=6) 624 sleep_time = next(backoff_) 625 _LOG.warning( 626 "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i", 627 response.status, 628 response.reason, 629 sleep_time, 630 self._max_retries - retries, 631 ) 632 633 retries += 1 634 await asyncio.sleep(sleep_time) 635 continue 636 637 raise await error.raise_error(response) 638 # eol 639 except _Dyn: 640 continue 641 642 if not typing.TYPE_CHECKING: 643 644 def __enter__(self) -> typing.NoReturn: 645 cls = type(self) 646 raise TypeError( 647 f"{cls.__qualname__} is async only, use 'async with' instead." 648 ) 649 650 def __exit__( 651 self, 652 exception_type: typing.Optional[type[BaseException]], 653 exception: typing.Optional[BaseException], 654 exception_traceback: typing.Optional[types.TracebackType], 655 ) -> None: 656 ... 657 658 async def __aenter__(self) -> RESTClient: 659 self._open() 660 return self 661 662 async def __aexit__( 663 self, 664 exception_type: typing.Optional[type[BaseException]], 665 exception: typing.Optional[BaseException], 666 exception_traceback: typing.Optional[types.TracebackType], 667 ) -> None: 668 await self.close() 669 670 # We don't want this to be super complicated. 671 @staticmethod 672 @typing.final 673 async def _handle_ratelimit( 674 response: aiohttp.ClientResponse, 675 method: str, 676 route: str, 677 max_ratelimit_retries: int = 3, 678 ) -> None: 679 680 if response.status != http.HTTPStatus.TOO_MANY_REQUESTS: 681 return 682 683 if response.content_type != _APP_JSON: 684 raise error.HTTPError( 685 f"Being ratelimited on non JSON request, {response.content_type}.", 686 http.HTTPStatus.TOO_MANY_REQUESTS, 687 ) 688 689 count: int = 0 690 json: typedefs.JSONObject = await response.json() 691 retry_after = float(json["ThrottleSeconds"]) 692 693 while True: 694 if count == max_ratelimit_retries: 695 raise _Dyn 696 697 if retry_after <= 0: 698 # We sleep for a little bit to avoid funky behavior. 699 sleep_time = float(random.random() + 0.93) / 2 700 701 _LOG.warning( 702 "We're being ratelimited with method %s route %s. Sleeping for %.2fs.", 703 method, 704 route, 705 sleep_time, 706 ) 707 count += 1 708 await asyncio.sleep(sleep_time) 709 continue 710 711 raise error.RateLimitedError( 712 body=json, 713 url=str(response.real_url), 714 retry_after=retry_after, 715 ) 716 717 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 718 719 if not isinstance(self._client_id, int): 720 raise TypeError( 721 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 722 ) 723 724 if not isinstance(self._client_secret, str): 725 raise TypeError( 726 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 727 ) 728 729 headers = { 730 "client_secret": self._client_secret, 731 } 732 733 data = ( 734 f"grant_type=authorization_code&code={code}" 735 f"&client_id={self._client_id}&client_secret={self._client_secret}" 736 ) 737 738 response = await self._request( 739 RequestMethod.POST, "", headers=headers, data=data, oauth2=True 740 ) 741 assert isinstance(response, dict) 742 return builders.OAuth2Response.build_response(response) 743 744 async def refresh_access_token( 745 self, refresh_token: str, / 746 ) -> builders.OAuth2Response: 747 if not isinstance(self._client_id, int): 748 raise TypeError( 749 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 750 ) 751 752 if not isinstance(self._client_secret, str): 753 raise TypeError( 754 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 755 ) 756 757 data = { 758 "grant_type": "refresh_token", 759 "refresh_token": refresh_token, 760 "client_id": self._client_id, 761 "client_secret": self._client_secret, 762 "Content-Type": "application/x-www-form-urlencoded", 763 } 764 765 response = await self._request(RequestMethod.POST, "", data=data, oauth2=True) 766 assert isinstance(response, dict) 767 return builders.OAuth2Response.build_response(response) 768 769 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 770 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 771 resp = await self._request( 772 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 773 ) 774 assert isinstance(resp, dict) 775 return resp 776 777 async def fetch_user_themes(self) -> typedefs.JSONArray: 778 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 779 resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/") 780 assert isinstance(resp, list) 781 return resp 782 783 async def fetch_membership_from_id( 784 self, 785 id: int, 786 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 787 /, 788 ) -> typedefs.JSONObject: 789 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 790 resp = await self._request( 791 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 792 ) 793 assert isinstance(resp, dict) 794 return resp 795 796 async def fetch_player( 797 self, 798 name: str, 799 code: int, 800 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 801 /, 802 ) -> typedefs.JSONArray: 803 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 804 resp = await self._request( 805 RequestMethod.POST, 806 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 807 json={"displayName": name, "displayNameCode": code}, 808 ) 809 assert isinstance(resp, list) 810 return resp 811 812 async def search_users(self, name: str, /) -> typedefs.JSONObject: 813 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 814 resp = await self._request( 815 RequestMethod.POST, 816 "User/Search/GlobalName/0", 817 json={"displayNamePrefix": name}, 818 ) 819 assert isinstance(resp, dict) 820 return resp 821 822 async def fetch_clan_from_id( 823 self, id: int, /, access_token: typing.Optional[str] = None 824 ) -> typedefs.JSONObject: 825 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 826 resp = await self._request( 827 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 828 ) 829 assert isinstance(resp, dict) 830 return resp 831 832 async def fetch_clan( 833 self, 834 name: str, 835 /, 836 access_token: typing.Optional[str] = None, 837 *, 838 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 839 ) -> typedefs.JSONObject: 840 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 841 resp = await self._request( 842 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 843 ) 844 assert isinstance(resp, dict) 845 return resp 846 847 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 848 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 849 resp = await self._request( 850 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 851 ) 852 assert isinstance(resp, dict) 853 return resp 854 855 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 856 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 857 resp = await self._request( 858 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 859 ) 860 assert isinstance(resp, list) 861 return resp 862 863 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 864 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 865 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 866 assert isinstance(resp, dict) 867 return resp 868 869 async def fetch_character( 870 self, 871 member_id: int, 872 membership_type: typedefs.IntAnd[enums.MembershipType], 873 character_id: int, 874 components: list[enums.ComponentType], 875 auth: typing.Optional[str] = None, 876 ) -> typedefs.JSONObject: 877 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 878 collector = _collect_components(components) 879 response = await self._request( 880 RequestMethod.GET, 881 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 882 f"Character/{character_id}/?components={collector}", 883 auth=auth, 884 ) 885 assert isinstance(response, dict) 886 return response 887 888 async def fetch_activities( 889 self, 890 member_id: int, 891 character_id: int, 892 mode: typedefs.IntAnd[enums.GameMode], 893 membership_type: typedefs.IntAnd[ 894 enums.MembershipType 895 ] = enums.MembershipType.ALL, 896 *, 897 page: int = 0, 898 limit: int = 1, 899 ) -> typedefs.JSONObject: 900 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 901 resp = await self._request( 902 RequestMethod.GET, 903 f"Destiny2/{int(membership_type)}/Account/" 904 f"{member_id}/Character/{character_id}/Stats/Activities" 905 f"/?mode={int(mode)}&count={limit}&page={page}", 906 ) 907 assert isinstance(resp, dict) 908 return resp 909 910 async def fetch_vendor_sales(self) -> typedefs.JSONObject: 911 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 912 resp = await self._request( 913 RequestMethod.GET, 914 f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}", 915 ) 916 assert isinstance(resp, dict) 917 return resp 918 919 async def fetch_profile( 920 self, 921 membership_id: int, 922 type: typedefs.IntAnd[enums.MembershipType], 923 components: list[enums.ComponentType], 924 auth: typing.Optional[str] = None, 925 ) -> typedefs.JSONObject: 926 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 927 collector = _collect_components(components) 928 response = await self._request( 929 RequestMethod.GET, 930 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 931 auth=auth, 932 ) 933 assert isinstance(response, dict) 934 return response 935 936 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 937 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 938 response = await self._request( 939 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 940 ) 941 assert isinstance(response, dict) 942 return response 943 944 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 945 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 946 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 947 assert isinstance(resp, dict) 948 return resp 949 950 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 951 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 952 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 953 assert isinstance(resp, dict) 954 return resp 955 956 async def fetch_groups_for_member( 957 self, 958 member_id: int, 959 member_type: typedefs.IntAnd[enums.MembershipType], 960 /, 961 *, 962 filter: int = 0, 963 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 964 ) -> typedefs.JSONObject: 965 resp = await self._request( 966 RequestMethod.GET, 967 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 968 ) 969 assert isinstance(resp, dict) 970 return resp 971 972 async def fetch_potential_groups_for_member( 973 self, 974 member_id: int, 975 member_type: typedefs.IntAnd[enums.MembershipType], 976 /, 977 *, 978 filter: int = 0, 979 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 980 ) -> typedefs.JSONObject: 981 resp = await self._request( 982 RequestMethod.GET, 983 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 984 ) 985 assert isinstance(resp, dict) 986 return resp 987 988 async def fetch_clan_members( 989 self, 990 clan_id: int, 991 /, 992 *, 993 name: typing.Optional[str] = None, 994 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 995 ) -> typedefs.JSONObject: 996 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 997 resp = await self._request( 998 RequestMethod.GET, 999 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 1000 ) 1001 assert isinstance(resp, dict) 1002 return resp 1003 1004 async def fetch_hardlinked_credentials( 1005 self, 1006 credential: int, 1007 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 1008 /, 1009 ) -> typedefs.JSONObject: 1010 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1011 resp = await self._request( 1012 RequestMethod.GET, 1013 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 1014 ) 1015 assert isinstance(resp, dict) 1016 return resp 1017 1018 async def fetch_user_credentials( 1019 self, access_token: str, membership_id: int, / 1020 ) -> typedefs.JSONArray: 1021 resp = await self._request( 1022 RequestMethod.GET, 1023 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 1024 auth=access_token, 1025 ) 1026 assert isinstance(resp, list) 1027 return resp 1028 1029 async def insert_socket_plug( 1030 self, 1031 action_token: str, 1032 /, 1033 instance_id: int, 1034 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1035 character_id: int, 1036 membership_type: typedefs.IntAnd[enums.MembershipType], 1037 ) -> typedefs.JSONObject: 1038 1039 if isinstance(plug, builders.PlugSocketBuilder): 1040 plug = plug.collect() 1041 1042 body = { 1043 "actionToken": action_token, 1044 "itemInstanceId": instance_id, 1045 "plug": plug, 1046 "characterId": character_id, 1047 "membershipType": int(membership_type), 1048 } 1049 resp = await self._request( 1050 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 1051 ) 1052 assert isinstance(resp, dict) 1053 return resp 1054 1055 async def insert_socket_plug_free( 1056 self, 1057 access_token: str, 1058 /, 1059 instance_id: int, 1060 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1061 character_id: int, 1062 membership_type: typedefs.IntAnd[enums.MembershipType], 1063 ) -> typedefs.JSONObject: 1064 1065 if isinstance(plug, builders.PlugSocketBuilder): 1066 plug = plug.collect() 1067 1068 body = { 1069 "itemInstanceId": instance_id, 1070 "plug": plug, 1071 "characterId": character_id, 1072 "membershipType": int(membership_type), 1073 } 1074 resp = await self._request( 1075 RequestMethod.POST, 1076 "Destiny2/Actions/Items/InsertSocketPlugFree", 1077 json=body, 1078 auth=access_token, 1079 ) 1080 assert isinstance(resp, dict) 1081 return resp 1082 1083 async def set_item_lock_state( 1084 self, 1085 access_token: str, 1086 state: bool, 1087 /, 1088 item_id: int, 1089 character_id: int, 1090 membership_type: typedefs.IntAnd[enums.MembershipType], 1091 ) -> int: 1092 body = { 1093 "state": state, 1094 "itemId": item_id, 1095 "characterId": character_id, 1096 "membership_type": int(membership_type), 1097 } 1098 response = await self._request( 1099 RequestMethod.POST, 1100 "Destiny2/Actions/Items/SetLockState", 1101 json=body, 1102 auth=access_token, 1103 ) 1104 assert isinstance(response, int) 1105 return response 1106 1107 async def set_quest_track_state( 1108 self, 1109 access_token: str, 1110 state: bool, 1111 /, 1112 item_id: int, 1113 character_id: int, 1114 membership_type: typedefs.IntAnd[enums.MembershipType], 1115 ) -> int: 1116 body = { 1117 "state": state, 1118 "itemId": item_id, 1119 "characterId": character_id, 1120 "membership_type": int(membership_type), 1121 } 1122 response = await self._request( 1123 RequestMethod.POST, 1124 "Destiny2/Actions/Items/SetTrackedState", 1125 json=body, 1126 auth=access_token, 1127 ) 1128 assert isinstance(response, int) 1129 return response 1130 1131 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1132 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1133 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1134 assert isinstance(path, dict) 1135 return path 1136 1137 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1138 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1139 _ensure_manifest_language(language) 1140 1141 content = await self.fetch_manifest_path() 1142 resp = await self._request( 1143 RequestMethod.GET, 1144 content["mobileWorldContentPaths"][language], 1145 unwrapping="read", 1146 base=True, 1147 ) 1148 assert isinstance(resp, bytes) 1149 return resp 1150 1151 async def download_manifest( 1152 self, 1153 language: str = "en", 1154 name: str = "manifest.sqlite3", 1155 *, 1156 force: bool = False, 1157 ) -> None: 1158 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1159 if os.path.exists(name): 1160 1161 if force: 1162 _LOG.debug("Forcing manifest download.") 1163 os.remove(name) 1164 1165 return await self.download_manifest(language, name, force=force) 1166 1167 else: 1168 raise FileExistsError( 1169 "Manifest file already exists, " 1170 "If you want to force download, set the `force` parameter to `True`." 1171 ) 1172 1173 _LOG.debug("Downloading manifest...") 1174 data_bytes = await self.read_manifest_bytes(language) 1175 await asyncio.get_running_loop().run_in_executor( 1176 None, _write_sqlite_bytes, data_bytes, name 1177 ) 1178 1179 async def download_json_manifest(self, language: str = "en") -> None: 1180 _ensure_manifest_language(language) 1181 1182 _LOG.debug("Downloading manifest JSON...") 1183 1184 content = await self.fetch_manifest_path() 1185 json_bytes = await self._request( 1186 RequestMethod.GET, 1187 content["jsonWorldContentPaths"][language], 1188 unwrapping="read", 1189 base=True, 1190 ) 1191 1192 await asyncio.get_running_loop().run_in_executor( 1193 None, _write_json_bytes, json_bytes 1194 ) 1195 _LOG.debug("Finished downloading manifest JSON.") 1196 1197 async def fetch_manifest_version(self) -> str: 1198 return typing.cast(str, (await self.fetch_manifest_path())["version"]) 1199 1200 async def fetch_linked_profiles( 1201 self, 1202 member_id: int, 1203 member_type: typedefs.IntAnd[enums.MembershipType], 1204 /, 1205 *, 1206 all: bool = False, 1207 ) -> typedefs.JSONObject: 1208 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1209 resp = await self._request( 1210 RequestMethod.GET, 1211 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1212 ) 1213 assert isinstance(resp, dict) 1214 return resp 1215 1216 async def fetch_clan_banners(self) -> typedefs.JSONObject: 1217 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1218 resp = await self._request( 1219 RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/" 1220 ) 1221 assert isinstance(resp, dict) 1222 return resp 1223 1224 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1225 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1226 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1227 assert isinstance(resp, dict) 1228 return resp 1229 1230 async def fetch_public_milestone_content( 1231 self, milestone_hash: int, / 1232 ) -> typedefs.JSONObject: 1233 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1234 resp = await self._request( 1235 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1236 ) 1237 assert isinstance(resp, dict) 1238 return resp 1239 1240 async def fetch_current_user_memberships( 1241 self, access_token: str, / 1242 ) -> typedefs.JSONObject: 1243 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1244 resp = await self._request( 1245 RequestMethod.GET, 1246 "User/GetMembershipsForCurrentUser/", 1247 auth=access_token, 1248 ) 1249 assert isinstance(resp, dict) 1250 return resp 1251 1252 async def equip_item( 1253 self, 1254 access_token: str, 1255 /, 1256 item_id: int, 1257 character_id: int, 1258 membership_type: typedefs.IntAnd[enums.MembershipType], 1259 ) -> None: 1260 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1261 payload = { 1262 "itemId": item_id, 1263 "characterId": character_id, 1264 "membershipType": int(membership_type), 1265 } 1266 1267 await self._request( 1268 RequestMethod.POST, 1269 "Destiny2/Actions/Items/EquipItem/", 1270 json=payload, 1271 auth=access_token, 1272 ) 1273 1274 async def equip_items( 1275 self, 1276 access_token: str, 1277 /, 1278 item_ids: list[int], 1279 character_id: int, 1280 membership_type: typedefs.IntAnd[enums.MembershipType], 1281 ) -> None: 1282 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1283 payload = { 1284 "itemIds": item_ids, 1285 "characterId": character_id, 1286 "membershipType": int(membership_type), 1287 } 1288 await self._request( 1289 RequestMethod.POST, 1290 "Destiny2/Actions/Items/EquipItems/", 1291 json=payload, 1292 auth=access_token, 1293 ) 1294 1295 async def ban_clan_member( 1296 self, 1297 access_token: str, 1298 /, 1299 group_id: int, 1300 membership_id: int, 1301 membership_type: typedefs.IntAnd[enums.MembershipType], 1302 *, 1303 length: int = 0, 1304 comment: undefined.UndefinedOr[str] = undefined.Undefined, 1305 ) -> None: 1306 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1307 payload = {"comment": str(comment), "length": length} 1308 await self._request( 1309 RequestMethod.POST, 1310 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1311 json=payload, 1312 auth=access_token, 1313 ) 1314 1315 async def unban_clan_member( 1316 self, 1317 access_token: str, 1318 /, 1319 group_id: int, 1320 membership_id: int, 1321 membership_type: typedefs.IntAnd[enums.MembershipType], 1322 ) -> None: 1323 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1324 await self._request( 1325 RequestMethod.POST, 1326 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1327 auth=access_token, 1328 ) 1329 1330 async def kick_clan_member( 1331 self, 1332 access_token: str, 1333 /, 1334 group_id: int, 1335 membership_id: int, 1336 membership_type: typedefs.IntAnd[enums.MembershipType], 1337 ) -> typedefs.JSONObject: 1338 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1339 resp = await self._request( 1340 RequestMethod.POST, 1341 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1342 auth=access_token, 1343 ) 1344 assert isinstance(resp, dict) 1345 return resp 1346 1347 async def edit_clan( 1348 self, 1349 access_token: str, 1350 /, 1351 group_id: int, 1352 *, 1353 name: typedefs.NoneOr[str] = None, 1354 about: typedefs.NoneOr[str] = None, 1355 motto: typedefs.NoneOr[str] = None, 1356 theme: typedefs.NoneOr[str] = None, 1357 tags: typedefs.NoneOr[collections.Sequence[str]] = None, 1358 is_public: typedefs.NoneOr[bool] = None, 1359 locale: typedefs.NoneOr[str] = None, 1360 avatar_image_index: typedefs.NoneOr[int] = None, 1361 membership_option: typedefs.NoneOr[ 1362 typedefs.IntAnd[enums.MembershipOption] 1363 ] = None, 1364 allow_chat: typedefs.NoneOr[bool] = None, 1365 chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None, 1366 call_sign: typedefs.NoneOr[str] = None, 1367 homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1368 enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None, 1369 default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1370 is_public_topic_admin: typedefs.NoneOr[bool] = None, 1371 ) -> None: 1372 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1373 payload = { 1374 "name": name, 1375 "about": about, 1376 "motto": motto, 1377 "theme": theme, 1378 "tags": tags, 1379 "isPublic": is_public, 1380 "avatarImageIndex": avatar_image_index, 1381 "isPublicTopicAdminOnly": is_public_topic_admin, 1382 "allowChat": allow_chat, 1383 "chatSecurity": chat_security, 1384 "callsign": call_sign, 1385 "homepage": homepage, 1386 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1387 "defaultPublicity": default_publicity, 1388 "locale": locale, 1389 } 1390 if membership_option is not None: 1391 payload["membershipOption"] = int(membership_option) 1392 1393 await self._request( 1394 RequestMethod.POST, 1395 f"GroupV2/{group_id}/Edit", 1396 json=payload, 1397 auth=access_token, 1398 ) 1399 1400 async def edit_clan_options( 1401 self, 1402 access_token: str, 1403 /, 1404 group_id: int, 1405 *, 1406 invite_permissions_override: typedefs.NoneOr[bool] = None, 1407 update_culture_permissionOverride: typedefs.NoneOr[bool] = None, 1408 host_guided_game_permission_override: typedefs.NoneOr[ 1409 typing.Literal[0, 1, 2] 1410 ] = None, 1411 update_banner_permission_override: typedefs.NoneOr[bool] = None, 1412 join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None, 1413 ) -> None: 1414 1415 payload = { 1416 "InvitePermissionOverride": invite_permissions_override, 1417 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1418 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1419 "UpdateBannerPermissionOverride": update_banner_permission_override, 1420 "JoinLevel": int(join_level) if join_level else None, 1421 } 1422 1423 await self._request( 1424 RequestMethod.POST, 1425 f"GroupV2/{group_id}/EditFounderOptions", 1426 json=payload, 1427 auth=access_token, 1428 ) 1429 1430 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1431 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1432 resp = await self._request( 1433 RequestMethod.GET, 1434 "Social/Friends/", 1435 auth=access_token, 1436 ) 1437 assert isinstance(resp, dict) 1438 return resp 1439 1440 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1441 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1442 resp = await self._request( 1443 RequestMethod.GET, 1444 "Social/Friends/Requests", 1445 auth=access_token, 1446 ) 1447 assert isinstance(resp, dict) 1448 return resp 1449 1450 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1451 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1452 await self._request( 1453 RequestMethod.POST, 1454 f"Social/Friends/Requests/Accept/{member_id}", 1455 auth=access_token, 1456 ) 1457 1458 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1459 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1460 await self._request( 1461 RequestMethod.POST, 1462 f"Social/Friends/Add/{member_id}", 1463 auth=access_token, 1464 ) 1465 1466 async def decline_friend_request( 1467 self, access_token: str, /, member_id: int 1468 ) -> None: 1469 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1470 await self._request( 1471 RequestMethod.POST, 1472 f"Social/Friends/Requests/Decline/{member_id}", 1473 auth=access_token, 1474 ) 1475 1476 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1477 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1478 await self._request( 1479 RequestMethod.POST, 1480 f"Social/Friends/Remove/{member_id}", 1481 auth=access_token, 1482 ) 1483 1484 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1485 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1486 await self._request( 1487 RequestMethod.POST, 1488 f"Social/Friends/Requests/Remove/{member_id}", 1489 auth=access_token, 1490 ) 1491 1492 async def approve_all_pending_group_users( 1493 self, 1494 access_token: str, 1495 /, 1496 group_id: int, 1497 message: undefined.UndefinedOr[str] = undefined.Undefined, 1498 ) -> None: 1499 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1500 await self._request( 1501 RequestMethod.POST, 1502 f"GroupV2/{group_id}/Members/ApproveAll", 1503 auth=access_token, 1504 json={"message": str(message)}, 1505 ) 1506 1507 async def deny_all_pending_group_users( 1508 self, 1509 access_token: str, 1510 /, 1511 group_id: int, 1512 *, 1513 message: undefined.UndefinedOr[str] = undefined.Undefined, 1514 ) -> None: 1515 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1516 await self._request( 1517 RequestMethod.POST, 1518 f"GroupV2/{group_id}/Members/DenyAll", 1519 auth=access_token, 1520 json={"message": str(message)}, 1521 ) 1522 1523 async def add_optional_conversation( 1524 self, 1525 access_token: str, 1526 /, 1527 group_id: int, 1528 *, 1529 name: undefined.UndefinedOr[str] = undefined.Undefined, 1530 security: typing.Literal[0, 1] = 0, 1531 ) -> None: 1532 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1533 payload = {"chatName": str(name), "chatSecurity": security} 1534 await self._request( 1535 RequestMethod.POST, 1536 f"GroupV2/{group_id}/OptionalConversations/Add", 1537 json=payload, 1538 auth=access_token, 1539 ) 1540 1541 async def edit_optional_conversation( 1542 self, 1543 access_token: str, 1544 /, 1545 group_id: int, 1546 conversation_id: int, 1547 *, 1548 name: undefined.UndefinedOr[str] = undefined.Undefined, 1549 security: typing.Literal[0, 1] = 0, 1550 enable_chat: bool = False, 1551 ) -> None: 1552 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1553 payload = { 1554 "chatEnabled": enable_chat, 1555 "chatName": str(name), 1556 "chatSecurity": security, 1557 } 1558 await self._request( 1559 RequestMethod.POST, 1560 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1561 json=payload, 1562 auth=access_token, 1563 ) 1564 1565 async def transfer_item( 1566 self, 1567 access_token: str, 1568 /, 1569 item_id: int, 1570 item_hash: int, 1571 character_id: int, 1572 member_type: typedefs.IntAnd[enums.MembershipType], 1573 *, 1574 stack_size: int = 1, 1575 vault: bool = False, 1576 ) -> None: 1577 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1578 payload = { 1579 "characterId": character_id, 1580 "membershipType": int(member_type), 1581 "itemId": item_id, 1582 "itemReferenceHash": item_hash, 1583 "stackSize": stack_size, 1584 "transferToVault": vault, 1585 } 1586 await self._request( 1587 RequestMethod.POST, 1588 "Destiny2/Actions/Items/TransferItem", 1589 json=payload, 1590 auth=access_token, 1591 ) 1592 1593 async def pull_item( 1594 self, 1595 access_token: str, 1596 /, 1597 item_id: int, 1598 item_hash: int, 1599 character_id: int, 1600 member_type: typedefs.IntAnd[enums.MembershipType], 1601 *, 1602 stack_size: int = 1, 1603 vault: bool = False, 1604 ) -> None: 1605 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1606 payload = { 1607 "characterId": character_id, 1608 "membershipType": int(member_type), 1609 "itemId": item_id, 1610 "itemReferenceHash": item_hash, 1611 "stackSize": stack_size, 1612 "transferToVault": vault, 1613 } 1614 await self._request( 1615 RequestMethod.POST, 1616 "Destiny2/Actions/Items/PullFromPostmaster", 1617 json=payload, 1618 auth=access_token, 1619 ) 1620 1621 async def fetch_fireteams( 1622 self, 1623 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1624 *, 1625 platform: typedefs.IntAnd[ 1626 fireteams.FireteamPlatform 1627 ] = fireteams.FireteamPlatform.ANY, 1628 language: typing.Union[ 1629 fireteams.FireteamLanguage, str 1630 ] = fireteams.FireteamLanguage.ALL, 1631 date_range: typedefs.IntAnd[ 1632 fireteams.FireteamDate 1633 ] = fireteams.FireteamDate.ALL, 1634 page: int = 0, 1635 slots_filter: int = 0, 1636 ) -> typedefs.JSONObject: 1637 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1638 resp = await self._request( 1639 RequestMethod.GET, 1640 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1641 ) 1642 assert isinstance(resp, dict) 1643 return resp 1644 1645 async def fetch_avaliable_clan_fireteams( 1646 self, 1647 access_token: str, 1648 group_id: int, 1649 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1650 *, 1651 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1652 language: typing.Union[fireteams.FireteamLanguage, str], 1653 date_range: typedefs.IntAnd[ 1654 fireteams.FireteamDate 1655 ] = fireteams.FireteamDate.ALL, 1656 page: int = 0, 1657 public_only: bool = False, 1658 slots_filter: int = 0, 1659 ) -> typedefs.JSONObject: 1660 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1661 resp = await self._request( 1662 RequestMethod.GET, 1663 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1664 json={"langFilter": str(language)}, 1665 auth=access_token, 1666 ) 1667 assert isinstance(resp, dict) 1668 return resp 1669 1670 async def fetch_clan_fireteam( 1671 self, access_token: str, fireteam_id: int, group_id: int 1672 ) -> typedefs.JSONObject: 1673 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1674 resp = await self._request( 1675 RequestMethod.GET, 1676 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1677 auth=access_token, 1678 ) 1679 assert isinstance(resp, dict) 1680 return resp 1681 1682 async def fetch_my_clan_fireteams( 1683 self, 1684 access_token: str, 1685 group_id: int, 1686 *, 1687 include_closed: bool = True, 1688 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1689 language: typing.Union[fireteams.FireteamLanguage, str], 1690 filtered: bool = True, 1691 page: int = 0, 1692 ) -> typedefs.JSONObject: 1693 payload = {"groupFilter": filtered, "langFilter": str(language)} 1694 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1695 resp = await self._request( 1696 RequestMethod.GET, 1697 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1698 json=payload, 1699 auth=access_token, 1700 ) 1701 assert isinstance(resp, dict) 1702 return resp 1703 1704 async def fetch_private_clan_fireteams( 1705 self, access_token: str, group_id: int, / 1706 ) -> int: 1707 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1708 resp = await self._request( 1709 RequestMethod.GET, 1710 f"Fireteam/Clan/{group_id}/ActiveCount", 1711 auth=access_token, 1712 ) 1713 assert isinstance(resp, int) 1714 return resp 1715 1716 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1717 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1718 resp = await self._request( 1719 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1720 ) 1721 assert isinstance(resp, dict) 1722 return resp 1723 1724 async def search_entities( 1725 self, name: str, entity_type: str, *, page: int = 0 1726 ) -> typedefs.JSONObject: 1727 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1728 resp = await self._request( 1729 RequestMethod.GET, 1730 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1731 json={"page": page}, 1732 ) 1733 assert isinstance(resp, dict) 1734 return resp 1735 1736 async def fetch_unique_weapon_history( 1737 self, 1738 membership_id: int, 1739 character_id: int, 1740 membership_type: typedefs.IntAnd[enums.MembershipType], 1741 ) -> typedefs.JSONObject: 1742 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1743 resp = await self._request( 1744 RequestMethod.GET, 1745 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1746 ) 1747 assert isinstance(resp, dict) 1748 return resp 1749 1750 async def fetch_item( 1751 self, 1752 member_id: int, 1753 item_id: int, 1754 membership_type: typedefs.IntAnd[enums.MembershipType], 1755 components: list[enums.ComponentType], 1756 ) -> typedefs.JSONObject: 1757 collector = _collect_components(components) 1758 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1759 resp = await self._request( 1760 RequestMethod.GET, 1761 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1762 ) 1763 assert isinstance(resp, dict) 1764 return resp 1765 1766 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1767 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1768 resp = await self._request( 1769 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1770 ) 1771 assert isinstance(resp, dict) 1772 return resp 1773 1774 async def fetch_available_locales(self) -> typedefs.JSONObject: 1775 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1776 resp = await self._request( 1777 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1778 ) 1779 assert isinstance(resp, dict) 1780 return resp 1781 1782 async def fetch_common_settings(self) -> typedefs.JSONObject: 1783 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1784 resp = await self._request(RequestMethod.GET, "Settings") 1785 assert isinstance(resp, dict) 1786 return resp 1787 1788 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1789 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1790 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1791 assert isinstance(resp, dict) 1792 return resp 1793 1794 async def fetch_global_alerts( 1795 self, *, include_streaming: bool = False 1796 ) -> typedefs.JSONArray: 1797 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1798 resp = await self._request( 1799 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1800 ) 1801 assert isinstance(resp, list) 1802 return resp 1803 1804 async def awainitialize_request( 1805 self, 1806 access_token: str, 1807 type: typing.Literal[0, 1], 1808 membership_type: typedefs.IntAnd[enums.MembershipType], 1809 /, 1810 *, 1811 affected_item_id: typing.Optional[int] = None, 1812 character_id: typing.Optional[int] = None, 1813 ) -> typedefs.JSONObject: 1814 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1815 1816 body = {"type": type, "membershipType": int(membership_type)} 1817 1818 if affected_item_id is not None: 1819 body["affectedItemId"] = affected_item_id 1820 1821 if character_id is not None: 1822 body["characterId"] = character_id 1823 1824 resp = await self._request( 1825 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1826 ) 1827 assert isinstance(resp, dict) 1828 return resp 1829 1830 async def awaget_action_token( 1831 self, access_token: str, correlation_id: str, / 1832 ) -> typedefs.JSONObject: 1833 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1834 resp = await self._request( 1835 RequestMethod.POST, 1836 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1837 auth=access_token, 1838 ) 1839 assert isinstance(resp, dict) 1840 return resp 1841 1842 async def awa_provide_authorization_result( 1843 self, 1844 access_token: str, 1845 selection: int, 1846 correlation_id: str, 1847 nonce: collections.MutableSequence[typing.Union[str, bytes]], 1848 ) -> int: 1849 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1850 1851 body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce} 1852 1853 resp = await self._request( 1854 RequestMethod.POST, 1855 "Destiny2/Awa/AwaProvideAuthorizationResult", 1856 json=body, 1857 auth=access_token, 1858 ) 1859 assert isinstance(resp, int) 1860 return resp 1861 1862 async def fetch_vendors( 1863 self, 1864 access_token: str, 1865 character_id: int, 1866 membership_id: int, 1867 membership_type: typedefs.IntAnd[enums.MembershipType], 1868 /, 1869 components: list[enums.ComponentType], 1870 filter: typing.Optional[int] = None, 1871 ) -> typedefs.JSONObject: 1872 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1873 components_ = _collect_components(components) 1874 route = ( 1875 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1876 f"/Character/{character_id}/Vendors/?components={components_}" 1877 ) 1878 1879 if filter is not None: 1880 route = route + f"&filter={filter}" 1881 1882 resp = await self._request( 1883 RequestMethod.GET, 1884 route, 1885 auth=access_token, 1886 ) 1887 assert isinstance(resp, dict) 1888 return resp 1889 1890 async def fetch_vendor( 1891 self, 1892 access_token: str, 1893 character_id: int, 1894 membership_id: int, 1895 membership_type: typedefs.IntAnd[enums.MembershipType], 1896 vendor_hash: int, 1897 /, 1898 components: list[enums.ComponentType], 1899 ) -> typedefs.JSONObject: 1900 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1901 components_ = _collect_components(components) 1902 resp = await self._request( 1903 RequestMethod.GET, 1904 ( 1905 f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}" 1906 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1907 ), 1908 auth=access_token, 1909 ) 1910 assert isinstance(resp, dict) 1911 return resp 1912 1913 async def fetch_application_api_usage( 1914 self, 1915 access_token: str, 1916 application_id: int, 1917 /, 1918 *, 1919 start: typing.Optional[datetime.datetime] = None, 1920 end: typing.Optional[datetime.datetime] = None, 1921 ) -> typedefs.JSONObject: 1922 1923 end_date, start_date = time.parse_date_range(end, start) 1924 resp = await self._request( 1925 RequestMethod.GET, 1926 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1927 auth=access_token, 1928 ) 1929 assert isinstance(resp, dict) 1930 return resp 1931 1932 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1933 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1934 assert isinstance(resp, list) 1935 return resp 1936 1937 async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject: 1938 resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/") 1939 assert isinstance(resp, dict) 1940 return resp 1941 1942 async def fetch_content_by_id( 1943 self, id: int, locale: str, /, *, head: bool = False 1944 ) -> typedefs.JSONObject: 1945 resp = await self._request( 1946 RequestMethod.GET, 1947 f"Content/GetContentById/{id}/{locale}/", 1948 json={"head": head}, 1949 ) 1950 assert isinstance(resp, dict) 1951 return resp 1952 1953 async def fetch_content_by_tag_and_type( 1954 self, locale: str, tag: str, type: str, *, head: bool = False 1955 ) -> typedefs.JSONObject: 1956 resp = await self._request( 1957 RequestMethod.GET, 1958 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1959 json={"head": head}, 1960 ) 1961 assert isinstance(resp, dict) 1962 return resp 1963 1964 async def search_content_with_text( 1965 self, 1966 locale: str, 1967 /, 1968 content_type: str, 1969 search_text: str, 1970 tag: str, 1971 *, 1972 page: undefined.UndefinedOr[int] = undefined.Undefined, 1973 source: undefined.UndefinedOr[str] = undefined.Undefined, 1974 ) -> typedefs.JSONObject: 1975 1976 body: typedefs.JSONObject = {} 1977 1978 body["ctype"] = content_type 1979 body["searchtext"] = search_text 1980 body["tag"] = tag 1981 1982 if page is not undefined.Undefined: 1983 body["currentpage"] = page 1984 else: 1985 body["currentpage"] = 1 1986 1987 if source is not undefined.Undefined: 1988 body["source"] = source 1989 else: 1990 source = "" 1991 resp = await self._request( 1992 RequestMethod.GET, f"Content/Search/{locale}/", json=body 1993 ) 1994 assert isinstance(resp, dict) 1995 return resp 1996 1997 async def search_content_by_tag_and_type( 1998 self, 1999 locale: str, 2000 tag: str, 2001 type: str, 2002 *, 2003 page: undefined.UndefinedOr[int] = undefined.Undefined, 2004 ) -> typedefs.JSONObject: 2005 body: typedefs.JSONObject = {} 2006 body["currentpage"] = 1 if page is undefined.Undefined else page 2007 resp = await self._request( 2008 RequestMethod.GET, 2009 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 2010 json=body, 2011 ) 2012 assert isinstance(resp, dict) 2013 return resp 2014 2015 async def search_help_articles( 2016 self, text: str, size: str, / 2017 ) -> typedefs.JSONObject: 2018 resp = await self._request( 2019 RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/" 2020 ) 2021 assert isinstance(resp, dict) 2022 return resp 2023 2024 async def fetch_topics_page( 2025 self, 2026 category_filter: int, 2027 group: int, 2028 date_filter: int, 2029 sort: typing.Union[str, bytes], 2030 *, 2031 page: undefined.UndefinedOr[int] = undefined.Undefined, 2032 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2033 tag_filter: undefined.UndefinedOr[str] = undefined.Undefined, 2034 ) -> typedefs.JSONObject: 2035 2036 body: typedefs.JSONObject = {} 2037 if locales is not undefined.Undefined: 2038 body["locales"] = ",".join(str(locales)) 2039 else: 2040 body["locales"] = ",".join([]) 2041 2042 if tag_filter is not undefined.Undefined: 2043 body["tagstring"] = tag_filter 2044 else: 2045 body["tagstring"] = "" 2046 2047 page = 0 if page is not undefined.Undefined else page 2048 2049 resp = await self._request( 2050 RequestMethod.GET, 2051 f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/", 2052 json=body, 2053 ) 2054 assert isinstance(resp, dict) 2055 return resp 2056 2057 async def fetch_core_topics_page( 2058 self, 2059 category_filter: int, 2060 date_filter: int, 2061 sort: typing.Union[str, bytes], 2062 *, 2063 page: undefined.UndefinedOr[int] = undefined.Undefined, 2064 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2065 ) -> typedefs.JSONObject: 2066 body: typedefs.JSONObject = {} 2067 2068 if locales is not undefined.Undefined: 2069 body["locales"] = ",".join(str(locales)) 2070 else: 2071 body["locales"] = ",".join([]) 2072 2073 resp = await self._request( 2074 RequestMethod.GET, 2075 f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}" 2076 f"/{sort!s}/{date_filter}/{category_filter}/", 2077 json=body, 2078 ) 2079 assert isinstance(resp, dict) 2080 return resp 2081 2082 async def fetch_posts_threaded_page( 2083 self, 2084 parent_post: bool, 2085 page: int, 2086 page_size: int, 2087 parent_post_id: int, 2088 reply_size: int, 2089 root_thread_mode: bool, 2090 sort_mode: int, 2091 show_banned: typing.Optional[str] = None, 2092 ) -> typedefs.JSONObject: 2093 resp = await self._request( 2094 RequestMethod.GET, 2095 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 2096 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 2097 json={"showbanned": show_banned}, 2098 ) 2099 assert isinstance(resp, dict) 2100 return resp 2101 2102 async def fetch_posts_threaded_page_from_child( 2103 self, 2104 child_id: bool, 2105 page: int, 2106 page_size: int, 2107 reply_size: int, 2108 root_thread_mode: bool, 2109 sort_mode: int, 2110 show_banned: typing.Optional[str] = None, 2111 ) -> typedefs.JSONObject: 2112 resp = await self._request( 2113 RequestMethod.GET, 2114 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 2115 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 2116 json={"showbanned": show_banned}, 2117 ) 2118 assert isinstance(resp, dict) 2119 return resp 2120 2121 async def fetch_post_and_parent( 2122 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2123 ) -> typedefs.JSONObject: 2124 resp = await self._request( 2125 RequestMethod.GET, 2126 f"Forum/GetPostAndParent/{child_id}/", 2127 json={"showbanned": show_banned}, 2128 ) 2129 assert isinstance(resp, dict) 2130 return resp 2131 2132 async def fetch_posts_and_parent_awaiting( 2133 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2134 ) -> typedefs.JSONObject: 2135 resp = await self._request( 2136 RequestMethod.GET, 2137 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 2138 json={"showbanned": show_banned}, 2139 ) 2140 assert isinstance(resp, dict) 2141 return resp 2142 2143 async def fetch_topic_for_content(self, content_id: int, /) -> int: 2144 resp = await self._request( 2145 RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/" 2146 ) 2147 assert isinstance(resp, int) 2148 return resp 2149 2150 async def fetch_forum_tag_suggestions( 2151 self, partial_tag: str, / 2152 ) -> typedefs.JSONObject: 2153 resp = await self._request( 2154 RequestMethod.GET, 2155 "Forum/GetForumTagSuggestions/", 2156 json={"partialtag": partial_tag}, 2157 ) 2158 assert isinstance(resp, dict) 2159 return resp 2160 2161 async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject: 2162 resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/") 2163 assert isinstance(resp, dict) 2164 return resp 2165 2166 async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray: 2167 resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/") 2168 assert isinstance(resp, list) 2169 return resp 2170 2171 async def fetch_recommended_groups( 2172 self, 2173 accecss_token: str, 2174 /, 2175 *, 2176 date_range: int = 0, 2177 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 2178 ) -> typedefs.JSONArray: 2179 resp = await self._request( 2180 RequestMethod.POST, 2181 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2182 auth=accecss_token, 2183 ) 2184 assert isinstance(resp, list) 2185 return resp 2186 2187 async def fetch_available_avatars(self) -> collections.Mapping[str, int]: 2188 resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/") 2189 assert isinstance(resp, dict) 2190 return resp 2191 2192 async def fetch_user_clan_invite_setting( 2193 self, 2194 access_token: str, 2195 /, 2196 membership_type: typedefs.IntAnd[enums.MembershipType], 2197 ) -> bool: 2198 resp = await self._request( 2199 RequestMethod.GET, 2200 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2201 auth=access_token, 2202 ) 2203 assert isinstance(resp, bool) 2204 return resp 2205 2206 async def fetch_banned_group_members( 2207 self, access_token: str, group_id: int, /, *, page: int = 1 2208 ) -> typedefs.JSONObject: 2209 resp = await self._request( 2210 RequestMethod.GET, 2211 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2212 auth=access_token, 2213 ) 2214 assert isinstance(resp, dict) 2215 return resp 2216 2217 async def fetch_pending_group_memberships( 2218 self, access_token: str, group_id: int, /, *, current_page: int = 1 2219 ) -> typedefs.JSONObject: 2220 resp = await self._request( 2221 RequestMethod.GET, 2222 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2223 auth=access_token, 2224 ) 2225 assert isinstance(resp, dict) 2226 return resp 2227 2228 async def fetch_invited_group_memberships( 2229 self, access_token: str, group_id: int, /, *, current_page: int = 1 2230 ) -> typedefs.JSONObject: 2231 resp = await self._request( 2232 RequestMethod.GET, 2233 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2234 auth=access_token, 2235 ) 2236 assert isinstance(resp, dict) 2237 return resp 2238 2239 async def invite_member_to_group( 2240 self, 2241 access_token: str, 2242 /, 2243 group_id: int, 2244 membership_id: int, 2245 membership_type: typedefs.IntAnd[enums.MembershipType], 2246 *, 2247 message: undefined.UndefinedOr[str] = undefined.Undefined, 2248 ) -> typedefs.JSONObject: 2249 resp = await self._request( 2250 RequestMethod.POST, 2251 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2252 auth=access_token, 2253 json={"message": str(message)}, 2254 ) 2255 assert isinstance(resp, dict) 2256 return resp 2257 2258 async def cancel_group_member_invite( 2259 self, 2260 access_token: str, 2261 /, 2262 group_id: int, 2263 membership_id: int, 2264 membership_type: typedefs.IntAnd[enums.MembershipType], 2265 ) -> typedefs.JSONObject: 2266 resp = await self._request( 2267 RequestMethod.POST, 2268 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2269 auth=access_token, 2270 ) 2271 assert isinstance(resp, dict) 2272 return resp 2273 2274 async def fetch_historical_definition(self) -> typedefs.JSONObject: 2275 resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/") 2276 assert isinstance(resp, dict) 2277 return resp 2278 2279 async def fetch_historical_stats( 2280 self, 2281 character_id: int, 2282 membership_id: int, 2283 membership_type: typedefs.IntAnd[enums.MembershipType], 2284 day_start: datetime.datetime, 2285 day_end: datetime.datetime, 2286 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2287 modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]], 2288 *, 2289 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2290 ) -> typedefs.JSONObject: 2291 2292 end, start = time.parse_date_range(day_end, day_start) 2293 resp = await self._request( 2294 RequestMethod.GET, 2295 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2296 json={ 2297 "dayend": end, 2298 "daystart": start, 2299 "groups": [str(int(group)) for group in groups], 2300 "modes": [str(int(mode)) for mode in modes], 2301 "periodType": int(period_type), 2302 }, 2303 ) 2304 assert isinstance(resp, dict) 2305 return resp 2306 2307 async def fetch_historical_stats_for_account( 2308 self, 2309 membership_id: int, 2310 membership_type: typedefs.IntAnd[enums.MembershipType], 2311 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2312 ) -> typedefs.JSONObject: 2313 resp = await self._request( 2314 RequestMethod.GET, 2315 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2316 json={"groups": [str(int(group)) for group in groups]}, 2317 ) 2318 assert isinstance(resp, dict) 2319 return resp 2320 2321 async def fetch_aggregated_activity_stats( 2322 self, 2323 character_id: int, 2324 membership_id: int, 2325 membership_type: typedefs.IntAnd[enums.MembershipType], 2326 /, 2327 ) -> typedefs.JSONObject: 2328 resp = await self._request( 2329 RequestMethod.GET, 2330 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2331 f"Character/{character_id}/Stats/AggregateActivityStats/", 2332 ) 2333 assert isinstance(resp, dict) 2334 return resp
A RESTful client implementation for Bungie's API.
This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.
This client is also used within aiobungie.Client which deserialize those returned JSON objects
using the factory into Pythonic data classes objects which provide Python functionality.
Example
import aiobungie
async def main():
async with aiobungie.RESTClient("TOKEN") as rest_client:
req = await rest_client.fetch_clan_members(4389205)
clan_members = req['results']
for member in clan_members:
for k, v in member['destinyUserInfo'].items():
print(k, v)
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
413 def __init__( 414 self, 415 token: str, 416 /, 417 client_secret: typing.Optional[str] = None, 418 client_id: typing.Optional[int] = None, 419 *, 420 max_retries: int = 4, 421 max_ratelimit_retries: int = 3, 422 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 423 ) -> None: 424 self._session: typing.Optional[_Session] = None 425 self._lock: typing.Optional[asyncio.Lock] = None 426 self._client_secret = client_secret 427 self._client_id = client_id 428 self._token: str = token 429 self._max_retries = max_retries 430 self._max_rate_limit_retries = max_ratelimit_retries 431 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 432 433 self._set_debug_level(enable_debugging)
A mutable mapping storage for the user's needs.
This mapping is useful for storing any kind of data that the user may need.
Example
import aiobungie
client = aiobungie.RESTClient(…)
async with client:
# Fetch auth tokens and store them
client.metadata["tokens"] = await client.fetch_access_token("code")
# Some other time.
async with client:
# Retrieve the tokens
tokens: aiobungie.OAuth2Response = client.metadata["tokens"]
# Use them to fetch your user.
user = await client.fetch_current_user_memberships(tokens.access_token)
447 @typing.final 448 async def close(self) -> None: 449 if self._session is not None: 450 await self._session.close() 451 self._session = None
Close this REST client session if it was acquired.
453 @typing.final 454 def enable_debugging( 455 self, 456 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 457 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 458 /, 459 ) -> None: 460 self._set_debug_level(level, file)
Enables debugging for the REST calls.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE"|aiobungie.TRACE: This will log the response headers along with the minimal information.
Parameters
- level (
str | bool | int): The level of debugging to enable. - file (
pathlib.Path | str | None): The file path to write the debug logs to. If provided.
462 @typing.final 463 async def static_request( 464 self, 465 method: typing.Union[RequestMethod, str], 466 path: str, 467 *, 468 auth: typing.Optional[str] = None, 469 json: typing.Optional[dict[str, typing.Any]] = None, 470 ) -> ResponseSig: 471 return await self._request(method, path, auth=auth, json=json)
Perform an HTTP request given a valid Bungie endpoint.
Parameters
- method (
aiobungie.RequestMethod | str): The request method, This may beGET,POST,PUT, etc. - path (
str): The Bungie endpoint or path. A path must look something like thisDestiny2/3/Profile/46111239123/... - auth (
str | None): An optional bearer token for methods that requires OAuth2 Authorization header. - json (
dict[str, typing.Any] | None): An optional JSON data to include in the request.
Returns
aiobungie.rest.ResponseSig: The response payload.
473 @typing.final 474 def build_oauth2_url( 475 self, client_id: typing.Optional[int] = None 476 ) -> typing.Optional[str]: 477 client_id = client_id or self._client_id 478 if client_id is None: 479 return None 480 481 return url.OAUTH2_EP_BUILDER.format( 482 oauth_endpoint=url.OAUTH_EP, 483 client_id=client_id, 484 uuid=_uuid(), 485 )
Builds an OAuth2 URL using the provided user REST/Base client secret/id.
Parameters
- client_id (
int | None): An optional client id to provide, If leftNoneit will roll back to the id passed to theRESTClient, If both isNonethis method will returnNone.
Returns
str | None: If the client id was provided as a parameter or provided inaiobungie.RESTClient, A complete URL will be returned. OtherwiseNonewill be returned.
717 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 718 719 if not isinstance(self._client_id, int): 720 raise TypeError( 721 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 722 ) 723 724 if not isinstance(self._client_secret, str): 725 raise TypeError( 726 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 727 ) 728 729 headers = { 730 "client_secret": self._client_secret, 731 } 732 733 data = ( 734 f"grant_type=authorization_code&code={code}" 735 f"&client_id={self._client_id}&client_secret={self._client_secret}" 736 ) 737 738 response = await self._request( 739 RequestMethod.POST, "", headers=headers, data=data, oauth2=True 740 ) 741 assert isinstance(response, dict) 742 return builders.OAuth2Response.build_response(response)
Makes a POST request and fetch the OAuth2 access_token and refresh token.
Parameters
- code (
str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
Raises
aiobungie.Unauthorized: The passed code was invalid.
744 async def refresh_access_token( 745 self, refresh_token: str, / 746 ) -> builders.OAuth2Response: 747 if not isinstance(self._client_id, int): 748 raise TypeError( 749 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 750 ) 751 752 if not isinstance(self._client_secret, str): 753 raise TypeError( 754 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 755 ) 756 757 data = { 758 "grant_type": "refresh_token", 759 "refresh_token": refresh_token, 760 "client_id": self._client_id, 761 "client_secret": self._client_secret, 762 "Content-Type": "application/x-www-form-urlencoded", 763 } 764 765 response = await self._request(RequestMethod.POST, "", data=data, oauth2=True) 766 assert isinstance(response, dict) 767 return builders.OAuth2Response.build_response(response)
Refresh OAuth2 access token given its refresh token.
Parameters
- refresh_token (
str): The refresh token.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
769 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 770 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 771 resp = await self._request( 772 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 773 ) 774 assert isinstance(resp, dict) 775 return resp
Fetch a Bungie user by their id.
Parameters
- id (
int): The user id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of users objects.
Raises
aiobungie.NotFound: The user was not found.
783 async def fetch_membership_from_id( 784 self, 785 id: int, 786 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 787 /, 788 ) -> typedefs.JSONObject: 789 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 790 resp = await self._request( 791 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 792 ) 793 assert isinstance(resp, dict) 794 return resp
Fetch Bungie user's memberships from their id.
Parameters
- id (
int): The user's id. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user.
Raises
- aiobungie.NotFound: The requested user was not found.
796 async def fetch_player( 797 self, 798 name: str, 799 code: int, 800 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 801 /, 802 ) -> typedefs.JSONArray: 803 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 804 resp = await self._request( 805 RequestMethod.POST, 806 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 807 json={"displayName": name, "displayNameCode": code}, 808 ) 809 assert isinstance(resp, list) 810 return resp
Fetch a Destiny 2 Player.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
aiobungie.typedefs.JSONArray: A JSON array of the found player's memberships.
Raises
aiobungie.NotFound: The player was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
812 async def search_users(self, name: str, /) -> typedefs.JSONObject: 813 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 814 resp = await self._request( 815 RequestMethod.POST, 816 "User/Search/GlobalName/0", 817 json={"displayNamePrefix": name}, 818 ) 819 assert isinstance(resp, dict) 820 return resp
Search for users by their global name and return all users who share this name.
Parameters
- name (
str): The user name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the found users.
Raises
aiobungie.NotFound: The user(s) was not found.
822 async def fetch_clan_from_id( 823 self, id: int, /, access_token: typing.Optional[str] = None 824 ) -> typedefs.JSONObject: 825 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 826 resp = await self._request( 827 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 828 ) 829 assert isinstance(resp, dict) 830 return resp
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
832 async def fetch_clan( 833 self, 834 name: str, 835 /, 836 access_token: typing.Optional[str] = None, 837 *, 838 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 839 ) -> typedefs.JSONObject: 840 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 841 resp = await self._request( 842 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 843 ) 844 assert isinstance(resp, dict) 845 return resp
Fetch a Clan by its name. This method will return the first clan found with given name name.
Parameters
- name (
str): The clan name.
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group type, Default is one.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
847 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 848 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 849 resp = await self._request( 850 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 851 ) 852 assert isinstance(resp, dict) 853 return resp
Fetch the admins and founder members of the clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan admins and founder members.
Raises
aiobungie.NotFound: The clan was not found.
855 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 856 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 857 resp = await self._request( 858 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 859 ) 860 assert isinstance(resp, list) 861 return resp
Fetch a clan's conversations.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the conversations.
863 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 864 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 865 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 866 assert isinstance(resp, dict) 867 return resp
Fetch a Bungie Application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application.
869 async def fetch_character( 870 self, 871 member_id: int, 872 membership_type: typedefs.IntAnd[enums.MembershipType], 873 character_id: int, 874 components: list[enums.ComponentType], 875 auth: typing.Optional[str] = None, 876 ) -> typedefs.JSONObject: 877 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 878 collector = _collect_components(components) 879 response = await self._request( 880 RequestMethod.GET, 881 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 882 f"Character/{character_id}/?components={collector}", 883 auth=auth, 884 ) 885 assert isinstance(response, dict) 886 return response
Fetch a Destiny 2 player's characters.
Parameters
- member_id (
int): A valid bungie member id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type. - character_id (
int): The character id to return. - components (
list[aiobungie.ComponentType]): A list of character components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the requested character.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
888 async def fetch_activities( 889 self, 890 member_id: int, 891 character_id: int, 892 mode: typedefs.IntAnd[enums.GameMode], 893 membership_type: typedefs.IntAnd[ 894 enums.MembershipType 895 ] = enums.MembershipType.ALL, 896 *, 897 page: int = 0, 898 limit: int = 1, 899 ) -> typedefs.JSONObject: 900 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 901 resp = await self._request( 902 RequestMethod.GET, 903 f"Destiny2/{int(membership_type)}/Account/" 904 f"{member_id}/Character/{character_id}/Stats/Activities" 905 f"/?mode={int(mode)}&count={limit}&page={page}", 906 ) 907 assert isinstance(resp, dict) 908 return resp
Fetch a Destiny 2 activity for the specified user id and character.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve. - mode (
aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Member ship type, if nothing was passed than it will return all. - page (
int): The page number. Default to1 - limit (
int): Limit the returned result. Default to1
Returns
aiobungie.typedefs.JSONObject: A JSON object of the player's activities.
Raises
aiobungie.NotFound: The activity was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
910 async def fetch_vendor_sales(self) -> typedefs.JSONObject: 911 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 912 resp = await self._request( 913 RequestMethod.GET, 914 f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}", 915 ) 916 assert isinstance(resp, dict) 917 return resp
919 async def fetch_profile( 920 self, 921 membership_id: int, 922 type: typedefs.IntAnd[enums.MembershipType], 923 components: list[enums.ComponentType], 924 auth: typing.Optional[str] = None, 925 ) -> typedefs.JSONObject: 926 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 927 collector = _collect_components(components) 928 response = await self._request( 929 RequestMethod.GET, 930 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 931 auth=auth, 932 ) 933 assert isinstance(response, dict) 934 return response
Fetch a bungie profile.
Parameters
- membership_id (
int): The member's id. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): A valid membership type. - components (
list[aiobungie.ComponentType]): A list of profile components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found profile.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
936 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 937 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 938 response = await self._request( 939 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 940 ) 941 assert isinstance(response, dict) 942 return response
Fetch a Destiny definition item given its type and hash.
Parameters
- type (
str): Entity's type definition. - hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the definition data.
944 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 945 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 946 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 947 assert isinstance(resp, dict) 948 return resp
Fetch a Destiny inventory item entity given a its hash.
Parameters
- hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the inventory item.
950 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 951 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 952 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 953 assert isinstance(resp, dict) 954 return resp
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the objetive data.
956 async def fetch_groups_for_member( 957 self, 958 member_id: int, 959 member_type: typedefs.IntAnd[enums.MembershipType], 960 /, 961 *, 962 filter: int = 0, 963 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 964 ) -> typedefs.JSONObject: 965 resp = await self._request( 966 RequestMethod.GET, 967 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 968 ) 969 assert isinstance(resp, dict) 970 return resp
Fetch the information about the groups for a member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
builsins.int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
972 async def fetch_potential_groups_for_member( 973 self, 974 member_id: int, 975 member_type: typedefs.IntAnd[enums.MembershipType], 976 /, 977 *, 978 filter: int = 0, 979 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 980 ) -> typedefs.JSONObject: 981 resp = await self._request( 982 RequestMethod.GET, 983 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 984 ) 985 assert isinstance(resp, dict) 986 return resp
Get information about the groups that a given member has applied to or been invited to.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
builsins.int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
988 async def fetch_clan_members( 989 self, 990 clan_id: int, 991 /, 992 *, 993 name: typing.Optional[str] = None, 994 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 995 ) -> typedefs.JSONObject: 996 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 997 resp = await self._request( 998 RequestMethod.GET, 999 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 1000 ) 1001 assert isinstance(resp, dict) 1002 return resp
Fetch all Bungie Clan members.
Parameters
- clan_id (
builsins.int): The clans id
Other Parameters
- name (
typing.Optional[str]): If provided, Only players matching this name will be returned. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): An optional clan member's membership type. Default is set toaiobungie.MembershipType.NONEWhich returns the first matched clan member by their name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of clan members.
Raises
aiobungie.NotFound: The clan was not found.
1004 async def fetch_hardlinked_credentials( 1005 self, 1006 credential: int, 1007 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 1008 /, 1009 ) -> typedefs.JSONObject: 1010 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1011 resp = await self._request( 1012 RequestMethod.GET, 1013 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 1014 ) 1015 assert isinstance(resp, dict) 1016 return resp
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.typedefs.IntAnd[aiobungie.CredentialType]): The crededntial type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user hard linked types.
1018 async def fetch_user_credentials( 1019 self, access_token: str, membership_id: int, / 1020 ) -> typedefs.JSONArray: 1021 resp = await self._request( 1022 RequestMethod.GET, 1023 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 1024 auth=access_token, 1025 ) 1026 assert isinstance(resp, list) 1027 return resp
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the returned credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1029 async def insert_socket_plug( 1030 self, 1031 action_token: str, 1032 /, 1033 instance_id: int, 1034 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1035 character_id: int, 1036 membership_type: typedefs.IntAnd[enums.MembershipType], 1037 ) -> typedefs.JSONObject: 1038 1039 if isinstance(plug, builders.PlugSocketBuilder): 1040 plug = plug.collect() 1041 1042 body = { 1043 "actionToken": action_token, 1044 "itemInstanceId": instance_id, 1045 "plug": plug, 1046 "characterId": character_id, 1047 "membershipType": int(membership_type), 1048 } 1049 resp = await self._request( 1050 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 1051 ) 1052 assert isinstance(resp, dict) 1053 return resp
Insert a plug into a socketed item.
OAuth2: AdvancedWriteActions scope is required
Parameters
- action_token (
str): Action token provided by the AwaGetActionToken API call. - instance_id (
int): The item instance id that's plug inserted. - plug (
typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType]
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1055 async def insert_socket_plug_free( 1056 self, 1057 access_token: str, 1058 /, 1059 instance_id: int, 1060 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1061 character_id: int, 1062 membership_type: typedefs.IntAnd[enums.MembershipType], 1063 ) -> typedefs.JSONObject: 1064 1065 if isinstance(plug, builders.PlugSocketBuilder): 1066 plug = plug.collect() 1067 1068 body = { 1069 "itemInstanceId": instance_id, 1070 "plug": plug, 1071 "characterId": character_id, 1072 "membershipType": int(membership_type), 1073 } 1074 resp = await self._request( 1075 RequestMethod.POST, 1076 "Destiny2/Actions/Items/InsertSocketPlugFree", 1077 json=body, 1078 auth=access_token, 1079 ) 1080 assert isinstance(resp, dict) 1081 return resp
Insert a plug into a socketed item. This doesn't require an Action token.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- instance_id (
int): The item instance id that's plug inserted. - plug (
typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType]
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1083 async def set_item_lock_state( 1084 self, 1085 access_token: str, 1086 state: bool, 1087 /, 1088 item_id: int, 1089 character_id: int, 1090 membership_type: typedefs.IntAnd[enums.MembershipType], 1091 ) -> int: 1092 body = { 1093 "state": state, 1094 "itemId": item_id, 1095 "characterId": character_id, 1096 "membership_type": int(membership_type), 1097 } 1098 response = await self._request( 1099 RequestMethod.POST, 1100 "Destiny2/Actions/Items/SetLockState", 1101 json=body, 1102 auth=access_token, 1103 ) 1104 assert isinstance(response, int) 1105 return response
Set the Lock State for an instanced item.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1107 async def set_quest_track_state( 1108 self, 1109 access_token: str, 1110 state: bool, 1111 /, 1112 item_id: int, 1113 character_id: int, 1114 membership_type: typedefs.IntAnd[enums.MembershipType], 1115 ) -> int: 1116 body = { 1117 "state": state, 1118 "itemId": item_id, 1119 "characterId": character_id, 1120 "membership_type": int(membership_type), 1121 } 1122 response = await self._request( 1123 RequestMethod.POST, 1124 "Destiny2/Actions/Items/SetTrackedState", 1125 json=body, 1126 auth=access_token, 1127 ) 1128 assert isinstance(response, int) 1129 return response
Set the Tracking State for an instanced Quest or Bounty.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1131 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1132 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1133 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1134 assert isinstance(path, dict) 1135 return path
Fetch the manifest JSON paths.
Returns
typedefs.JSONObject: The manifest JSON paths.
1137 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1138 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1139 _ensure_manifest_language(language) 1140 1141 content = await self.fetch_manifest_path() 1142 resp = await self._request( 1143 RequestMethod.GET, 1144 content["mobileWorldContentPaths"][language], 1145 unwrapping="read", 1146 base=True, 1147 ) 1148 assert isinstance(resp, bytes) 1149 return resp
Read raw manifest SQLite database bytes response.
This method can be used to write the bytes to zipped file and then extract it to get the manifest content.
Parameters
- language (
str): The manifest database language bytes to get.
Returns
bytes: The bytes to read and write the manifest database.
1151 async def download_manifest( 1152 self, 1153 language: str = "en", 1154 name: str = "manifest.sqlite3", 1155 *, 1156 force: bool = False, 1157 ) -> None: 1158 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1159 if os.path.exists(name): 1160 1161 if force: 1162 _LOG.debug("Forcing manifest download.") 1163 os.remove(name) 1164 1165 return await self.download_manifest(language, name, force=force) 1166 1167 else: 1168 raise FileExistsError( 1169 "Manifest file already exists, " 1170 "If you want to force download, set the `force` parameter to `True`." 1171 ) 1172 1173 _LOG.debug("Downloading manifest...") 1174 data_bytes = await self.read_manifest_bytes(language) 1175 await asyncio.get_running_loop().run_in_executor( 1176 None, _write_sqlite_bytes, data_bytes, name 1177 )
A helper method to download the manifest.
Note
This method downloads the sqlite database and not JSON.
Use RESTInterface.download_json_manifest for the JSON version.
Parameters
- language (
str): The manifest language to download, Default is english. - name (
str): The manifest database file name. Default ismanifest.sqlite3 - force (
bool): Whether to force the download. Default isFalse. However if set to true the old file will get removed and a new one will being to download.
Returns
None
1179 async def download_json_manifest(self, language: str = "en") -> None: 1180 _ensure_manifest_language(language) 1181 1182 _LOG.debug("Downloading manifest JSON...") 1183 1184 content = await self.fetch_manifest_path() 1185 json_bytes = await self._request( 1186 RequestMethod.GET, 1187 content["jsonWorldContentPaths"][language], 1188 unwrapping="read", 1189 base=True, 1190 ) 1191 1192 await asyncio.get_running_loop().run_in_executor( 1193 None, _write_json_bytes, json_bytes 1194 ) 1195 _LOG.debug("Finished downloading manifest JSON.")
Download the Bungie manifest json file.
Parameters
- language (
str): The language to download the manifest in.
1197 async def fetch_manifest_version(self) -> str: 1198 return typing.cast(str, (await self.fetch_manifest_path())["version"])
Fetch the manifest version.
Returns
str: The manifest version.
1200 async def fetch_linked_profiles( 1201 self, 1202 member_id: int, 1203 member_type: typedefs.IntAnd[enums.MembershipType], 1204 /, 1205 *, 1206 all: bool = False, 1207 ) -> typedefs.JSONObject: 1208 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1209 resp = await self._request( 1210 RequestMethod.GET, 1211 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1212 ) 1213 assert isinstance(resp, dict) 1214 return resp
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether thry're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.typedefs.JSONObject- A JSON object which contains an Array of profiles, an Array of profiles with errors and Bungie.Net membership
1224 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1225 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1226 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1227 assert isinstance(resp, dict) 1228 return resp
Fetch the available milestones.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information about the milestones.
1230 async def fetch_public_milestone_content( 1231 self, milestone_hash: int, / 1232 ) -> typedefs.JSONObject: 1233 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1234 resp = await self._request( 1235 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1236 ) 1237 assert isinstance(resp, dict) 1238 return resp
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information related to the fetched milestone.
1240 async def fetch_current_user_memberships( 1241 self, access_token: str, / 1242 ) -> typedefs.JSONObject: 1243 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1244 resp = await self._request( 1245 RequestMethod.GET, 1246 "User/GetMembershipsForCurrentUser/", 1247 auth=access_token, 1248 ) 1249 assert isinstance(resp, dict) 1250 return resp
Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.
This requires OAuth2 scope enabled and the valid Bearer access_token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the bungie net user and destiny memberships of this account.
1252 async def equip_item( 1253 self, 1254 access_token: str, 1255 /, 1256 item_id: int, 1257 character_id: int, 1258 membership_type: typedefs.IntAnd[enums.MembershipType], 1259 ) -> None: 1260 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1261 payload = { 1262 "itemId": item_id, 1263 "characterId": character_id, 1264 "membershipType": int(membership_type), 1265 } 1266 1267 await self._request( 1268 RequestMethod.POST, 1269 "Destiny2/Actions/Items/EquipItem/", 1270 json=payload, 1271 auth=access_token, 1272 )
Equip an item to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item id. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
1274 async def equip_items( 1275 self, 1276 access_token: str, 1277 /, 1278 item_ids: list[int], 1279 character_id: int, 1280 membership_type: typedefs.IntAnd[enums.MembershipType], 1281 ) -> None: 1282 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1283 payload = { 1284 "itemIds": item_ids, 1285 "characterId": character_id, 1286 "membershipType": int(membership_type), 1287 } 1288 await self._request( 1289 RequestMethod.POST, 1290 "Destiny2/Actions/Items/EquipItems/", 1291 json=payload, 1292 auth=access_token, 1293 )
Equip multiple items to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_ids (
list[int]): A list of item ids. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
1295 async def ban_clan_member( 1296 self, 1297 access_token: str, 1298 /, 1299 group_id: int, 1300 membership_id: int, 1301 membership_type: typedefs.IntAnd[enums.MembershipType], 1302 *, 1303 length: int = 0, 1304 comment: undefined.UndefinedOr[str] = undefined.Undefined, 1305 ) -> None: 1306 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1307 payload = {"comment": str(comment), "length": length} 1308 await self._request( 1309 RequestMethod.POST, 1310 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1311 json=payload, 1312 auth=access_token, 1313 )
Bans a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to ban. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- length (
int): An optional ban length. - comment (
aiobungie.UndefinedOr[str]): An optional comment to this ban. Default isUNDEFINED
1315 async def unban_clan_member( 1316 self, 1317 access_token: str, 1318 /, 1319 group_id: int, 1320 membership_id: int, 1321 membership_type: typedefs.IntAnd[enums.MembershipType], 1322 ) -> None: 1323 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1324 await self._request( 1325 RequestMethod.POST, 1326 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1327 auth=access_token, 1328 )
Unbans a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to unban. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
1330 async def kick_clan_member( 1331 self, 1332 access_token: str, 1333 /, 1334 group_id: int, 1335 membership_id: int, 1336 membership_type: typedefs.IntAnd[enums.MembershipType], 1337 ) -> typedefs.JSONObject: 1338 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1339 resp = await self._request( 1340 RequestMethod.POST, 1341 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1342 auth=access_token, 1343 ) 1344 assert isinstance(resp, dict) 1345 return resp
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the group that the member has been kicked from.
1347 async def edit_clan( 1348 self, 1349 access_token: str, 1350 /, 1351 group_id: int, 1352 *, 1353 name: typedefs.NoneOr[str] = None, 1354 about: typedefs.NoneOr[str] = None, 1355 motto: typedefs.NoneOr[str] = None, 1356 theme: typedefs.NoneOr[str] = None, 1357 tags: typedefs.NoneOr[collections.Sequence[str]] = None, 1358 is_public: typedefs.NoneOr[bool] = None, 1359 locale: typedefs.NoneOr[str] = None, 1360 avatar_image_index: typedefs.NoneOr[int] = None, 1361 membership_option: typedefs.NoneOr[ 1362 typedefs.IntAnd[enums.MembershipOption] 1363 ] = None, 1364 allow_chat: typedefs.NoneOr[bool] = None, 1365 chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None, 1366 call_sign: typedefs.NoneOr[str] = None, 1367 homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1368 enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None, 1369 default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1370 is_public_topic_admin: typedefs.NoneOr[bool] = None, 1371 ) -> None: 1372 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1373 payload = { 1374 "name": name, 1375 "about": about, 1376 "motto": motto, 1377 "theme": theme, 1378 "tags": tags, 1379 "isPublic": is_public, 1380 "avatarImageIndex": avatar_image_index, 1381 "isPublicTopicAdminOnly": is_public_topic_admin, 1382 "allowChat": allow_chat, 1383 "chatSecurity": chat_security, 1384 "callsign": call_sign, 1385 "homepage": homepage, 1386 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1387 "defaultPublicity": default_publicity, 1388 "locale": locale, 1389 } 1390 if membership_option is not None: 1391 payload["membershipOption"] = int(membership_option) 1392 1393 await self._request( 1394 RequestMethod.POST, 1395 f"GroupV2/{group_id}/Edit", 1396 json=payload, 1397 auth=access_token, 1398 )
Edit a clan.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id to edit.
Other Parameters
- name (
aiobungie.typedefs.NoneOr[str]): The name to edit the clan with. - about (
aiobungie.typedefs.NoneOr[str]): The about section to edit the clan with. - motto (
aiobungie.typedefs.NoneOr[str]): The motto section to edit the clan with. - theme (
aiobungie.typedefs.NoneOr[str]): The theme name to edit the clan with. - tags (
aiobungie.typedefs.NoneOr[collections.Sequence[str]]): A sequence of strings to replace the clan tags with. - is_public (
aiobungie.typedefs.NoneOr[bool]): If provided and set toTrue, The clan will set to private. If provided and set toFalse, The clan will set to public whether it was or not. - locale (
aiobungie.typedefs.NoneOr[str]): The locale section to edit the clan with. - avatar_image_index (
aiobungie.typedefs.NoneOr[int]): The clan avatar image index to edit the clan with. - membership_option :
aiobungie.typedefs.NoneOr[aiobungie.typedefs.IntAnd[aiobungie.MembershipOption]]# noqa (E501 # Line too long): The clan membership option to edit it with. - allow_chat (
aiobungie.typedefs.NoneOr[bool]): If provided and set toTrue, The clan members will be allowed to chat. If provided and set toFalse, The clan members will not be allowed to chat. - chat_security (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1]]): If provided and set to0, The clan chat security will be edited toGrouponly. If provided and set to1, The clan chat security will be edited toAdminonly. - call_sign (
aiobungie.typedefs.NoneOr[str]): The clan call sign to edit it with. - homepage (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat homepage will be edited toWall. If provided and set to1, The clan chat homepage will be edited toForum. If provided and set to0, The clan chat homepage will be edited toAllianceForum. - enable_invite_messaging_for_admins (
aiobungie.typedefs.NoneOr[bool]): ??? - default_publicity (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat publicity will be edited toPublic. If provided and set to1, The clan chat publicity will be edited toAlliance. If provided and set to2, The clan chat publicity will be edited toPrivate. - is_public_topic_admin (
aiobungie.typedefs.NoneOr[bool]): ???
1400 async def edit_clan_options( 1401 self, 1402 access_token: str, 1403 /, 1404 group_id: int, 1405 *, 1406 invite_permissions_override: typedefs.NoneOr[bool] = None, 1407 update_culture_permissionOverride: typedefs.NoneOr[bool] = None, 1408 host_guided_game_permission_override: typedefs.NoneOr[ 1409 typing.Literal[0, 1, 2] 1410 ] = None, 1411 update_banner_permission_override: typedefs.NoneOr[bool] = None, 1412 join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None, 1413 ) -> None: 1414 1415 payload = { 1416 "InvitePermissionOverride": invite_permissions_override, 1417 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1418 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1419 "UpdateBannerPermissionOverride": update_banner_permission_override, 1420 "JoinLevel": int(join_level) if join_level else None, 1421 } 1422 1423 await self._request( 1424 RequestMethod.POST, 1425 f"GroupV2/{group_id}/EditFounderOptions", 1426 json=payload, 1427 auth=access_token, 1428 )
Edit the clan options.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id.
Other Parameters
- invite_permissions_override (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - update_culture_permissionOverride (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - host_guided_game_permission_override (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides:0-> None,1-> Beginner2-> Member. Default is Member for clans, None for groups, although this means nothing for groups. - update_banner_permission_override (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - join_level (
aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default isaiobungie.ClanMemberType.BEGINNER
1430 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1431 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1432 resp = await self._request( 1433 RequestMethod.GET, 1434 "Social/Friends/", 1435 auth=access_token, 1436 ) 1437 assert isinstance(resp, dict) 1438 return resp
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the bungie friends's data.
1440 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1441 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1442 resp = await self._request( 1443 RequestMethod.GET, 1444 "Social/Friends/Requests", 1445 auth=access_token, 1446 ) 1447 assert isinstance(resp, dict) 1448 return resp
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of incoming requests and outgoing requests.
1450 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1451 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1452 await self._request( 1453 RequestMethod.POST, 1454 f"Social/Friends/Requests/Accept/{member_id}", 1455 auth=access_token, 1456 )
Accepts a friend relationship with the target user. The user must be on your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to accept.
1458 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1459 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1460 await self._request( 1461 RequestMethod.POST, 1462 f"Social/Friends/Add/{member_id}", 1463 auth=access_token, 1464 )
Requests a friend relationship with the target user.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to send the request to.
1466 async def decline_friend_request( 1467 self, access_token: str, /, member_id: int 1468 ) -> None: 1469 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1470 await self._request( 1471 RequestMethod.POST, 1472 f"Social/Friends/Requests/Decline/{member_id}", 1473 auth=access_token, 1474 )
Decline a friend request with the target user. The user must be in your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to decline.
1476 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1477 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1478 await self._request( 1479 RequestMethod.POST, 1480 f"Social/Friends/Remove/{member_id}", 1481 auth=access_token, 1482 )
Removes a friend from your friend list. The user must be in your friend list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove.
1484 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1485 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1486 await self._request( 1487 RequestMethod.POST, 1488 f"Social/Friends/Requests/Remove/{member_id}", 1489 auth=access_token, 1490 )
Removes a friend from your friend list requests. The user must be in your outgoing request list.
.. note : This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove from the requested friend list.
1492 async def approve_all_pending_group_users( 1493 self, 1494 access_token: str, 1495 /, 1496 group_id: int, 1497 message: undefined.UndefinedOr[str] = undefined.Undefined, 1498 ) -> None: 1499 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1500 await self._request( 1501 RequestMethod.POST, 1502 f"GroupV2/{group_id}/Members/ApproveAll", 1503 auth=access_token, 1504 json={"message": str(message)}, 1505 )
Apporve all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1507 async def deny_all_pending_group_users( 1508 self, 1509 access_token: str, 1510 /, 1511 group_id: int, 1512 *, 1513 message: undefined.UndefinedOr[str] = undefined.Undefined, 1514 ) -> None: 1515 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1516 await self._request( 1517 RequestMethod.POST, 1518 f"GroupV2/{group_id}/Members/DenyAll", 1519 auth=access_token, 1520 json={"message": str(message)}, 1521 )
Deny all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1523 async def add_optional_conversation( 1524 self, 1525 access_token: str, 1526 /, 1527 group_id: int, 1528 *, 1529 name: undefined.UndefinedOr[str] = undefined.Undefined, 1530 security: typing.Literal[0, 1] = 0, 1531 ) -> None: 1532 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1533 payload = {"chatName": str(name), "chatSecurity": security} 1534 await self._request( 1535 RequestMethod.POST, 1536 f"GroupV2/{group_id}/OptionalConversations/Add", 1537 json=payload, 1538 auth=access_token, 1539 )
Add a new chat channel to a group.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other parameters
name: aiobungie.UndefinedOr[str]
The chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
1541 async def edit_optional_conversation( 1542 self, 1543 access_token: str, 1544 /, 1545 group_id: int, 1546 conversation_id: int, 1547 *, 1548 name: undefined.UndefinedOr[str] = undefined.Undefined, 1549 security: typing.Literal[0, 1] = 0, 1550 enable_chat: bool = False, 1551 ) -> None: 1552 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1553 payload = { 1554 "chatEnabled": enable_chat, 1555 "chatName": str(name), 1556 "chatSecurity": security, 1557 } 1558 await self._request( 1559 RequestMethod.POST, 1560 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1561 json=payload, 1562 auth=access_token, 1563 )
Edit the settings of this chat channel.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id. - conversation_id (
int): The conversation/chat id.
Other parameters
name: aiobungie.UndefinedOr[str]
The new chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The new security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
enable_chat : bool
Whether to enable chatting or not.
If set to True then chatting will be enabled. Otherwise it will be disabled.
1565 async def transfer_item( 1566 self, 1567 access_token: str, 1568 /, 1569 item_id: int, 1570 item_hash: int, 1571 character_id: int, 1572 member_type: typedefs.IntAnd[enums.MembershipType], 1573 *, 1574 stack_size: int = 1, 1575 vault: bool = False, 1576 ) -> None: 1577 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1578 payload = { 1579 "characterId": character_id, 1580 "membershipType": int(member_type), 1581 "itemId": item_id, 1582 "itemReferenceHash": item_hash, 1583 "stackSize": stack_size, 1584 "transferToVault": vault, 1585 } 1586 await self._request( 1587 RequestMethod.POST, 1588 "Destiny2/Actions/Items/TransferItem", 1589 json=payload, 1590 auth=access_token, 1591 )
Transfer an item from / to your vault.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id you to transfer. - item_hash (
int): The item hash. - character_id (
int): The character id to transfer the item from/to. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - valut (
bool): Whether to trasnfer this item to your valut or not. Defaults toFalse.
1593 async def pull_item( 1594 self, 1595 access_token: str, 1596 /, 1597 item_id: int, 1598 item_hash: int, 1599 character_id: int, 1600 member_type: typedefs.IntAnd[enums.MembershipType], 1601 *, 1602 stack_size: int = 1, 1603 vault: bool = False, 1604 ) -> None: 1605 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1606 payload = { 1607 "characterId": character_id, 1608 "membershipType": int(member_type), 1609 "itemId": item_id, 1610 "itemReferenceHash": item_hash, 1611 "stackSize": stack_size, 1612 "transferToVault": vault, 1613 } 1614 await self._request( 1615 RequestMethod.POST, 1616 "Destiny2/Actions/Items/PullFromPostmaster", 1617 json=payload, 1618 auth=access_token, 1619 )
pull an item from the postmaster.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id to pull. - item_hash (
int): The item hash. - character_id (
int): The character id to pull the item to. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - valut (
bool): Whether to pill this item to your valut or not. Defaults toFalse.
1621 async def fetch_fireteams( 1622 self, 1623 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1624 *, 1625 platform: typedefs.IntAnd[ 1626 fireteams.FireteamPlatform 1627 ] = fireteams.FireteamPlatform.ANY, 1628 language: typing.Union[ 1629 fireteams.FireteamLanguage, str 1630 ] = fireteams.FireteamLanguage.ALL, 1631 date_range: typedefs.IntAnd[ 1632 fireteams.FireteamDate 1633 ] = fireteams.FireteamDate.ALL, 1634 page: int = 0, 1635 slots_filter: int = 0, 1636 ) -> typedefs.JSONObject: 1637 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1638 resp = await self._request( 1639 RequestMethod.GET, 1640 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1641 ) 1642 assert isinstance(resp, dict) 1643 return resp
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1645 async def fetch_avaliable_clan_fireteams( 1646 self, 1647 access_token: str, 1648 group_id: int, 1649 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1650 *, 1651 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1652 language: typing.Union[fireteams.FireteamLanguage, str], 1653 date_range: typedefs.IntAnd[ 1654 fireteams.FireteamDate 1655 ] = fireteams.FireteamDate.ALL, 1656 page: int = 0, 1657 public_only: bool = False, 1658 slots_filter: int = 0, 1659 ) -> typedefs.JSONObject: 1660 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1661 resp = await self._request( 1662 RequestMethod.GET, 1663 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1664 json={"langFilter": str(language)}, 1665 auth=access_token, 1666 ) 1667 assert isinstance(resp, dict) 1668 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1670 async def fetch_clan_fireteam( 1671 self, access_token: str, fireteam_id: int, group_id: int 1672 ) -> typedefs.JSONObject: 1673 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1674 resp = await self._request( 1675 RequestMethod.GET, 1676 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1677 auth=access_token, 1678 ) 1679 assert isinstance(resp, dict) 1680 return resp
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1682 async def fetch_my_clan_fireteams( 1683 self, 1684 access_token: str, 1685 group_id: int, 1686 *, 1687 include_closed: bool = True, 1688 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1689 language: typing.Union[fireteams.FireteamLanguage, str], 1690 filtered: bool = True, 1691 page: int = 0, 1692 ) -> typedefs.JSONObject: 1693 payload = {"groupFilter": filtered, "langFilter": str(language)} 1694 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1695 resp = await self._request( 1696 RequestMethod.GET, 1697 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1698 json=payload, 1699 auth=access_token, 1700 ) 1701 assert isinstance(resp, dict) 1702 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch.
Other Parameters
- include_closed (
bool): If provided and set toTrue, It will also return closed fireteams. If provided and set toFalse, It will only return public fireteams. Default isTrue. - platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - filtered (
bool): If set toTrue, it will filter by clan. Otherwise not. Default isTrue. - page (
int): The page number. By default its0which returns all available activities.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1704 async def fetch_private_clan_fireteams( 1705 self, access_token: str, group_id: int, / 1706 ) -> int: 1707 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1708 resp = await self._request( 1709 RequestMethod.GET, 1710 f"Fireteam/Clan/{group_id}/ActiveCount", 1711 auth=access_token, 1712 ) 1713 assert isinstance(resp, int) 1714 return resp
Fetch the active count of the clan fireteams that are only private.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id.
Returns
int: The active fireteams count. Max value returned is 25.
1716 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1717 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1718 resp = await self._request( 1719 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1720 ) 1721 assert isinstance(resp, dict) 1722 return resp
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the post activity.
1724 async def search_entities( 1725 self, name: str, entity_type: str, *, page: int = 0 1726 ) -> typedefs.JSONObject: 1727 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1728 resp = await self._request( 1729 RequestMethod.GET, 1730 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1731 json={"page": page}, 1732 ) 1733 assert isinstance(resp, dict) 1734 return resp
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinition
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the searched term.
1736 async def fetch_unique_weapon_history( 1737 self, 1738 membership_id: int, 1739 character_id: int, 1740 membership_type: typedefs.IntAnd[enums.MembershipType], 1741 ) -> typedefs.JSONObject: 1742 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1743 resp = await self._request( 1744 RequestMethod.GET, 1745 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1746 ) 1747 assert isinstance(resp, dict) 1748 return resp
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the returned weapons.
1750 async def fetch_item( 1751 self, 1752 member_id: int, 1753 item_id: int, 1754 membership_type: typedefs.IntAnd[enums.MembershipType], 1755 components: list[enums.ComponentType], 1756 ) -> typedefs.JSONObject: 1757 collector = _collect_components(components) 1758 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1759 resp = await self._request( 1760 RequestMethod.GET, 1761 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1762 ) 1763 assert isinstance(resp, dict) 1764 return resp
Fetch an instanced Destiny 2 item's details.
Parameters
- member_id (
int): The membership id of the Destiny 2 player. - item_id (
int): The instance id of the item. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type of the Destiny 2 player. - components (
list[aiobungie.ComponentType]): A list of components to retrieve.
Returns
aiobungie.typedefs.JSONObject: A JSON object response contains the fetched item with its components.
1766 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1767 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1768 resp = await self._request( 1769 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1770 ) 1771 assert isinstance(resp, dict) 1772 return resp
Fetch the weekly reward state for a clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON response of the clan rewards state.
1774 async def fetch_available_locales(self) -> typedefs.JSONObject: 1775 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1776 resp = await self._request( 1777 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1778 ) 1779 assert isinstance(resp, dict) 1780 return resp
Fetch available locales at Bungie.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains a list of all available localization cultures.
1782 async def fetch_common_settings(self) -> typedefs.JSONObject: 1783 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1784 resp = await self._request(RequestMethod.GET, "Settings") 1785 assert isinstance(resp, dict) 1786 return resp
Fetch the common settings used by Bungie's envirotment.
Returns
aiobungie.typedefs.JSONObject: The common settings JSON object.
1788 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1789 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1790 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1791 assert isinstance(resp, dict) 1792 return resp
Fetch a user's specific system overrides.
Returns
aiobungie.typedefs.JSONObject: The system overrides JSON object.
1794 async def fetch_global_alerts( 1795 self, *, include_streaming: bool = False 1796 ) -> typedefs.JSONArray: 1797 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1798 resp = await self._request( 1799 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1800 ) 1801 assert isinstance(resp, list) 1802 return resp
Fetch any active global alerts.
Parameters
- include_streaming (
bool): If True, the returned results will include streaming alerts. Default is False.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the global alerts objects.
1804 async def awainitialize_request( 1805 self, 1806 access_token: str, 1807 type: typing.Literal[0, 1], 1808 membership_type: typedefs.IntAnd[enums.MembershipType], 1809 /, 1810 *, 1811 affected_item_id: typing.Optional[int] = None, 1812 character_id: typing.Optional[int] = None, 1813 ) -> typedefs.JSONObject: 1814 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1815 1816 body = {"type": type, "membershipType": int(membership_type)} 1817 1818 if affected_item_id is not None: 1819 body["affectedItemId"] = affected_item_id 1820 1821 if character_id is not None: 1822 body["characterId"] = character_id 1823 1824 resp = await self._request( 1825 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1826 ) 1827 assert isinstance(resp, dict) 1828 return resp
Initialize a request to perform an advanced write action.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - type (
typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means itNone. Otherwise if 1 that means its insert plugs. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type of the account to modify.
Other Parameters
- affected_item_id (
typing.Optional[int]): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values. - character_id (
typing.Optional[int]): The Destiny character ID to perform this action on.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1830 async def awaget_action_token( 1831 self, access_token: str, correlation_id: str, / 1832 ) -> typedefs.JSONObject: 1833 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1834 resp = await self._request( 1835 RequestMethod.POST, 1836 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1837 auth=access_token, 1838 ) 1839 assert isinstance(resp, dict) 1840 return resp
Returns the action token if user approves the request.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - correlation_id (
str): The identifier for the advanced write action request.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1862 async def fetch_vendors( 1863 self, 1864 access_token: str, 1865 character_id: int, 1866 membership_id: int, 1867 membership_type: typedefs.IntAnd[enums.MembershipType], 1868 /, 1869 components: list[enums.ComponentType], 1870 filter: typing.Optional[int] = None, 1871 ) -> typedefs.JSONObject: 1872 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1873 components_ = _collect_components(components) 1874 route = ( 1875 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1876 f"/Character/{character_id}/Vendors/?components={components_}" 1877 ) 1878 1879 if filter is not None: 1880 route = route + f"&filter={filter}" 1881 1882 resp = await self._request( 1883 RequestMethod.GET, 1884 route, 1885 auth=access_token, 1886 ) 1887 assert isinstance(resp, dict) 1888 return resp
Get currently available vendors from the list of vendors that can possibly have rotating inventory.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
- filter (
int): Filters the type of items returned from the vendor. This can be left toNone.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1890 async def fetch_vendor( 1891 self, 1892 access_token: str, 1893 character_id: int, 1894 membership_id: int, 1895 membership_type: typedefs.IntAnd[enums.MembershipType], 1896 vendor_hash: int, 1897 /, 1898 components: list[enums.ComponentType], 1899 ) -> typedefs.JSONObject: 1900 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1901 components_ = _collect_components(components) 1902 resp = await self._request( 1903 RequestMethod.GET, 1904 ( 1905 f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}" 1906 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1907 ), 1908 auth=access_token, 1909 ) 1910 assert isinstance(resp, dict) 1911 return resp
Fetch details for a specific vendor.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for. - vendor_hash (
int): The vendor hash to return the details for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1913 async def fetch_application_api_usage( 1914 self, 1915 access_token: str, 1916 application_id: int, 1917 /, 1918 *, 1919 start: typing.Optional[datetime.datetime] = None, 1920 end: typing.Optional[datetime.datetime] = None, 1921 ) -> typedefs.JSONObject: 1922 1923 end_date, start_date = time.parse_date_range(end, start) 1924 resp = await self._request( 1925 RequestMethod.GET, 1926 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1927 auth=access_token, 1928 ) 1929 assert isinstance(resp, dict) 1930 return resp
Fetch a Bungie application's API usage.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - application_id (
int): The application id to get.
Other Parameters
start (
typing.Optional[datetime.datetime]): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.If this is left to
None. It will return the last 24 hours.end (
typing.Optional[datetime.datetime]): A datetime object can be used to collect the end of the application usage.If this is left to
None. It will returnnow.
Example
import datetime
# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
start=datetime.datetime(2021, 12, 10), end=datetime.datetime(2021, 12, 20)
)
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application usage details.
1932 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1933 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1934 assert isinstance(resp, list) 1935 return resp
Fetch details for applications created by Bungie.
Returns
aiobungie.typedefs.JSONArray: An array of Bungie created applications.
1942 async def fetch_content_by_id( 1943 self, id: int, locale: str, /, *, head: bool = False 1944 ) -> typedefs.JSONObject: 1945 resp = await self._request( 1946 RequestMethod.GET, 1947 f"Content/GetContentById/{id}/{locale}/", 1948 json={"head": head}, 1949 ) 1950 assert isinstance(resp, dict) 1951 return resp
1953 async def fetch_content_by_tag_and_type( 1954 self, locale: str, tag: str, type: str, *, head: bool = False 1955 ) -> typedefs.JSONObject: 1956 resp = await self._request( 1957 RequestMethod.GET, 1958 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1959 json={"head": head}, 1960 ) 1961 assert isinstance(resp, dict) 1962 return resp
1964 async def search_content_with_text( 1965 self, 1966 locale: str, 1967 /, 1968 content_type: str, 1969 search_text: str, 1970 tag: str, 1971 *, 1972 page: undefined.UndefinedOr[int] = undefined.Undefined, 1973 source: undefined.UndefinedOr[str] = undefined.Undefined, 1974 ) -> typedefs.JSONObject: 1975 1976 body: typedefs.JSONObject = {} 1977 1978 body["ctype"] = content_type 1979 body["searchtext"] = search_text 1980 body["tag"] = tag 1981 1982 if page is not undefined.Undefined: 1983 body["currentpage"] = page 1984 else: 1985 body["currentpage"] = 1 1986 1987 if source is not undefined.Undefined: 1988 body["source"] = source 1989 else: 1990 source = "" 1991 resp = await self._request( 1992 RequestMethod.GET, f"Content/Search/{locale}/", json=body 1993 ) 1994 assert isinstance(resp, dict) 1995 return resp
1997 async def search_content_by_tag_and_type( 1998 self, 1999 locale: str, 2000 tag: str, 2001 type: str, 2002 *, 2003 page: undefined.UndefinedOr[int] = undefined.Undefined, 2004 ) -> typedefs.JSONObject: 2005 body: typedefs.JSONObject = {} 2006 body["currentpage"] = 1 if page is undefined.Undefined else page 2007 resp = await self._request( 2008 RequestMethod.GET, 2009 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 2010 json=body, 2011 ) 2012 assert isinstance(resp, dict) 2013 return resp
2024 async def fetch_topics_page( 2025 self, 2026 category_filter: int, 2027 group: int, 2028 date_filter: int, 2029 sort: typing.Union[str, bytes], 2030 *, 2031 page: undefined.UndefinedOr[int] = undefined.Undefined, 2032 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2033 tag_filter: undefined.UndefinedOr[str] = undefined.Undefined, 2034 ) -> typedefs.JSONObject: 2035 2036 body: typedefs.JSONObject = {} 2037 if locales is not undefined.Undefined: 2038 body["locales"] = ",".join(str(locales)) 2039 else: 2040 body["locales"] = ",".join([]) 2041 2042 if tag_filter is not undefined.Undefined: 2043 body["tagstring"] = tag_filter 2044 else: 2045 body["tagstring"] = "" 2046 2047 page = 0 if page is not undefined.Undefined else page 2048 2049 resp = await self._request( 2050 RequestMethod.GET, 2051 f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/", 2052 json=body, 2053 ) 2054 assert isinstance(resp, dict) 2055 return resp
2057 async def fetch_core_topics_page( 2058 self, 2059 category_filter: int, 2060 date_filter: int, 2061 sort: typing.Union[str, bytes], 2062 *, 2063 page: undefined.UndefinedOr[int] = undefined.Undefined, 2064 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2065 ) -> typedefs.JSONObject: 2066 body: typedefs.JSONObject = {} 2067 2068 if locales is not undefined.Undefined: 2069 body["locales"] = ",".join(str(locales)) 2070 else: 2071 body["locales"] = ",".join([]) 2072 2073 resp = await self._request( 2074 RequestMethod.GET, 2075 f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}" 2076 f"/{sort!s}/{date_filter}/{category_filter}/", 2077 json=body, 2078 ) 2079 assert isinstance(resp, dict) 2080 return resp
2082 async def fetch_posts_threaded_page( 2083 self, 2084 parent_post: bool, 2085 page: int, 2086 page_size: int, 2087 parent_post_id: int, 2088 reply_size: int, 2089 root_thread_mode: bool, 2090 sort_mode: int, 2091 show_banned: typing.Optional[str] = None, 2092 ) -> typedefs.JSONObject: 2093 resp = await self._request( 2094 RequestMethod.GET, 2095 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 2096 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 2097 json={"showbanned": show_banned}, 2098 ) 2099 assert isinstance(resp, dict) 2100 return resp
2102 async def fetch_posts_threaded_page_from_child( 2103 self, 2104 child_id: bool, 2105 page: int, 2106 page_size: int, 2107 reply_size: int, 2108 root_thread_mode: bool, 2109 sort_mode: int, 2110 show_banned: typing.Optional[str] = None, 2111 ) -> typedefs.JSONObject: 2112 resp = await self._request( 2113 RequestMethod.GET, 2114 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 2115 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 2116 json={"showbanned": show_banned}, 2117 ) 2118 assert isinstance(resp, dict) 2119 return resp
2121 async def fetch_post_and_parent( 2122 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2123 ) -> typedefs.JSONObject: 2124 resp = await self._request( 2125 RequestMethod.GET, 2126 f"Forum/GetPostAndParent/{child_id}/", 2127 json={"showbanned": show_banned}, 2128 ) 2129 assert isinstance(resp, dict) 2130 return resp
2132 async def fetch_posts_and_parent_awaiting( 2133 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2134 ) -> typedefs.JSONObject: 2135 resp = await self._request( 2136 RequestMethod.GET, 2137 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 2138 json={"showbanned": show_banned}, 2139 ) 2140 assert isinstance(resp, dict) 2141 return resp
2171 async def fetch_recommended_groups( 2172 self, 2173 accecss_token: str, 2174 /, 2175 *, 2176 date_range: int = 0, 2177 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 2178 ) -> typedefs.JSONArray: 2179 resp = await self._request( 2180 RequestMethod.POST, 2181 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2182 auth=accecss_token, 2183 ) 2184 assert isinstance(resp, list) 2185 return resp
2192 async def fetch_user_clan_invite_setting( 2193 self, 2194 access_token: str, 2195 /, 2196 membership_type: typedefs.IntAnd[enums.MembershipType], 2197 ) -> bool: 2198 resp = await self._request( 2199 RequestMethod.GET, 2200 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2201 auth=access_token, 2202 ) 2203 assert isinstance(resp, bool) 2204 return resp
2206 async def fetch_banned_group_members( 2207 self, access_token: str, group_id: int, /, *, page: int = 1 2208 ) -> typedefs.JSONObject: 2209 resp = await self._request( 2210 RequestMethod.GET, 2211 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2212 auth=access_token, 2213 ) 2214 assert isinstance(resp, dict) 2215 return resp
2217 async def fetch_pending_group_memberships( 2218 self, access_token: str, group_id: int, /, *, current_page: int = 1 2219 ) -> typedefs.JSONObject: 2220 resp = await self._request( 2221 RequestMethod.GET, 2222 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2223 auth=access_token, 2224 ) 2225 assert isinstance(resp, dict) 2226 return resp
2228 async def fetch_invited_group_memberships( 2229 self, access_token: str, group_id: int, /, *, current_page: int = 1 2230 ) -> typedefs.JSONObject: 2231 resp = await self._request( 2232 RequestMethod.GET, 2233 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2234 auth=access_token, 2235 ) 2236 assert isinstance(resp, dict) 2237 return resp
2239 async def invite_member_to_group( 2240 self, 2241 access_token: str, 2242 /, 2243 group_id: int, 2244 membership_id: int, 2245 membership_type: typedefs.IntAnd[enums.MembershipType], 2246 *, 2247 message: undefined.UndefinedOr[str] = undefined.Undefined, 2248 ) -> typedefs.JSONObject: 2249 resp = await self._request( 2250 RequestMethod.POST, 2251 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2252 auth=access_token, 2253 json={"message": str(message)}, 2254 ) 2255 assert isinstance(resp, dict) 2256 return resp
2258 async def cancel_group_member_invite( 2259 self, 2260 access_token: str, 2261 /, 2262 group_id: int, 2263 membership_id: int, 2264 membership_type: typedefs.IntAnd[enums.MembershipType], 2265 ) -> typedefs.JSONObject: 2266 resp = await self._request( 2267 RequestMethod.POST, 2268 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2269 auth=access_token, 2270 ) 2271 assert isinstance(resp, dict) 2272 return resp
2279 async def fetch_historical_stats( 2280 self, 2281 character_id: int, 2282 membership_id: int, 2283 membership_type: typedefs.IntAnd[enums.MembershipType], 2284 day_start: datetime.datetime, 2285 day_end: datetime.datetime, 2286 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2287 modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]], 2288 *, 2289 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2290 ) -> typedefs.JSONObject: 2291 2292 end, start = time.parse_date_range(day_end, day_start) 2293 resp = await self._request( 2294 RequestMethod.GET, 2295 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2296 json={ 2297 "dayend": end, 2298 "daystart": start, 2299 "groups": [str(int(group)) for group in groups], 2300 "modes": [str(int(mode)) for mode in modes], 2301 "periodType": int(period_type), 2302 }, 2303 ) 2304 assert isinstance(resp, dict) 2305 return resp
Fetch historical stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - day_start (
datetime.datetime): The start of the day to return the stats for. - day_end (
datetime.datetime): The end of the day to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return. - modes (
list[aiobungie.GameMode | int]): A list of game modes to return. - period_type (
aiobungie.enums.PeriodType): The period type to return the stats for. This will returnALL_TIMEby default if not modified.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats.
2307 async def fetch_historical_stats_for_account( 2308 self, 2309 membership_id: int, 2310 membership_type: typedefs.IntAnd[enums.MembershipType], 2311 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2312 ) -> typedefs.JSONObject: 2313 resp = await self._request( 2314 RequestMethod.GET, 2315 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2316 json={"groups": [str(int(group)) for group in groups]}, 2317 ) 2318 assert isinstance(resp, dict) 2319 return resp
Fetch historical stats for an account's membership.
Parameters
- membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats for the account. This includes both the character and account stats.
2321 async def fetch_aggregated_activity_stats( 2322 self, 2323 character_id: int, 2324 membership_id: int, 2325 membership_type: typedefs.IntAnd[enums.MembershipType], 2326 /, 2327 ) -> typedefs.JSONObject: 2328 resp = await self._request( 2329 RequestMethod.GET, 2330 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2331 f"Character/{character_id}/Stats/AggregateActivityStats/", 2332 ) 2333 assert isinstance(resp, dict) 2334 return resp
Fetch aggregated activity stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the aggregated activity stats.
232class RESTPool: 233 """Pool of `RESTClient` instances. 234 235 This allows to create multiple instances of `RESTClient`s that can be acquired 236 which share the same connector and metadata. 237 238 Example 239 ------- 240 ```py 241 import aiobungie 242 import asyncio 243 244 client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret') 245 246 # Using a context manager to acquire an instance 247 # of the pool and close the connection after finishing. 248 249 async def first() -> str: 250 async with client_pool.acquire() as client: 251 return client.build_oauth2_url() 252 253 async def second() -> None: 254 async with client_pool.acquire() as client: 255 new_tokens = await client.refresh_access_token("token") 256 client.metadata['tokens'] = new_tokens 257 258 # Client instances are independent from first and second. 259 await asyncio.gather(first(), second()) 260 ``` 261 262 Parameters 263 ---------- 264 token : `str` 265 A valid application token from Bungie's developer portal. 266 267 Other Parameters 268 ---------------- 269 max_retries : `int` 270 The max retries number to retry if the request hit a `5xx` status code. 271 max_ratelimit_retries : `int` 272 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 273 client_secret : `typing.Optional[str]` 274 An optional application client secret, 275 This is only needed if you're fetching OAuth2 tokens with this client. 276 client_id : `typing.Optional[int]` 277 An optional application client id, 278 This is only needed if you're fetching OAuth2 tokens with this client. 279 enable_debugging : `bool | str` 280 Whether to enable logging responses or not. 281 282 Logging Levels 283 -------------- 284 * `False`: This will disable logging. 285 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 286 Like the response status, route, taken time and so on. 287 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 288 """ 289 290 __slots__ = ( 291 "_token", 292 "_max_retries", 293 "_client_secret", 294 "_client_id", 295 "_max_rate_limit_retries", 296 "_metadata", 297 "_enable_debug", 298 ) 299 300 # Looks like mypy doesn't like this. 301 if typing.TYPE_CHECKING: 302 _enable_debug: typing.Union[typing.Literal["TRACE"], bool, int] 303 304 def __init__( 305 self, 306 token: str, 307 /, 308 client_secret: typing.Optional[str] = None, 309 client_id: typing.Optional[int] = None, 310 *, 311 max_retries: int = 4, 312 max_rate_limit_retries: int = 3, 313 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 314 ) -> None: 315 self._client_secret = client_secret 316 self._client_id = client_id 317 self._token: str = token 318 self._max_retries = max_retries 319 self._max_rate_limit_retries = max_rate_limit_retries 320 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 321 self._enable_debug = enable_debugging 322 323 @property 324 def client_id(self) -> typing.Optional[int]: 325 return self._client_id 326 327 @property 328 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 329 """Pool's Metadata. This is different from client instance metadata.""" 330 return self._metadata 331 332 @typing.final 333 def acquire(self) -> RESTClient: 334 """Acquires a new `RESTClient` instance from this REST pool. 335 336 Returns 337 ------- 338 `RESTClient` 339 An instance of a REST client. 340 """ 341 instance = RESTClient( 342 self._token, 343 client_secret=self._client_secret, 344 client_id=self._client_id, 345 max_retries=self._max_retries, 346 max_ratelimit_retries=self._max_rate_limit_retries, 347 enable_debugging=self._enable_debug, 348 ) 349 return instance
Pool of RESTClient instances.
This allows to create multiple instances of RESTClients that can be acquired
which share the same connector and metadata.
Example
import aiobungie
import asyncio
client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
# Using a context manager to acquire an instance
# of the pool and close the connection after finishing.
async def first() -> str:
async with client_pool.acquire() as client:
return client.build_oauth2_url()
async def second() -> None:
async with client_pool.acquire() as client:
new_tokens = await client.refresh_access_token("token")
client.metadata['tokens'] = new_tokens
# Client instances are independent from first and second.
await asyncio.gather(first(), second())
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information. Like the response status, route, taken time and so on."TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
304 def __init__( 305 self, 306 token: str, 307 /, 308 client_secret: typing.Optional[str] = None, 309 client_id: typing.Optional[int] = None, 310 *, 311 max_retries: int = 4, 312 max_rate_limit_retries: int = 3, 313 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 314 ) -> None: 315 self._client_secret = client_secret 316 self._client_id = client_id 317 self._token: str = token 318 self._max_retries = max_retries 319 self._max_rate_limit_retries = max_rate_limit_retries 320 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 321 self._enable_debug = enable_debugging
Pool's Metadata. This is different from client instance metadata.
332 @typing.final 333 def acquire(self) -> RESTClient: 334 """Acquires a new `RESTClient` instance from this REST pool. 335 336 Returns 337 ------- 338 `RESTClient` 339 An instance of a REST client. 340 """ 341 instance = RESTClient( 342 self._token, 343 client_secret=self._client_secret, 344 client_id=self._client_id, 345 max_retries=self._max_retries, 346 max_ratelimit_retries=self._max_rate_limit_retries, 347 enable_debugging=self._enable_debug, 348 ) 349 return instance
Acquires a new RESTClient instance from this REST pool.
Returns
RESTClient: An instance of a REST client.
496@typing.final 497class Race(int, Enum): 498 """An Enum for Destiny races.""" 499 500 HUMAN = 0 501 AWOKEN = 1 502 EXO = 2 503 UNKNOWN = 3
An Enum for Destiny races.
148@typing.final 149class Raid(int, Enum): 150 """An Enum for all available raids in Destiny 2.""" 151 152 DSC = 910380154 153 """Deep Stone Crypt""" 154 155 LW = 2122313384 156 """Last Wish""" 157 158 VOG = 3881495763 159 """Normal Valut of Glass""" 160 161 GOS = 3458480158 162 """Garden Of Salvation"""
An Enum for all available raids in Destiny 2.
200@attrs.define(auto_exc=True) 201class RateLimitedError(HTTPError): 202 """Raised when being hit with ratelimits.""" 203 204 http_status: http.HTTPStatus = attrs.field( 205 default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False 206 ) 207 """The request response http status.""" 208 209 url: typedefs.StrOrURL 210 """The URL/endpoint caused this error.""" 211 212 body: typing.Any 213 """The response body.""" 214 215 retry_after: float = attrs.field(default=0.0) 216 """The amount of seconds you need to wait before retrying to requests.""" 217 218 message: str = attrs.field(init=False) 219 """A Bungie human readable message describes the cause of the error.""" 220 221 @message.default # type: ignore 222 def _(self) -> str: 223 return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!" 224 225 def __str__(self) -> str: 226 return self.message
Raised when being hit with ratelimits.
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default): 3 self.http_status = attr_dict['http_status'].default 4 self.url = url 5 self.body = body 6 self.retry_after = retry_after 7 self.message = __attr_factory_message(self) 8 BaseException.__init__(self, self.url,self.body,self.retry_after)
Method generated by attrs for class RateLimitedError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
49@typing.final 50class RecordState(enums.Flag): 51 """An enum for records component states.""" 52 53 NONE = 0 54 REDEEMED = 1 55 UNAVAILABLE = 2 56 OBJECTIVE_NOT_COMPLETED = 4 57 OBSCURED = 8 58 INVISIBLE = 16 59 ENTITLEMENT_UNOWNED = 32 60 CAN_EQUIP_TITLE = 64
An enum for records component states.
691@typing.final 692class Relationship(int, Enum): 693 """An enum for bungie friends relationship types.""" 694 695 UNKNOWN = 0 696 FRIEND = 1 697 INCOMING_REQUEST = 2 698 OUTGOING_REQUEST = 3
An enum for bungie friends relationship types.
213class RequestMethod(str, enums.Enum): 214 """HTTP request methods enum.""" 215 216 GET = "GET" 217 """GET methods.""" 218 POST = "POST" 219 """POST methods.""" 220 PUT = "PUT" 221 """PUT methods.""" 222 PATCH = "PATCH" 223 """PATCH methods.""" 224 DELETE = "DELETE" 225 """DELETE methods"""
HTTP request methods enum.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
195@attrs.define(auto_exc=True) 196class ResponseError(HTTPException): 197 """Standard HTTP responses exception."""
Standard HTTP responses exception.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class ResponseError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
- args
518@typing.final 519class Stat(int, Enum): 520 """An Enum for Destiny 2 character stats.""" 521 522 NONE = 0 523 MOBILITY = 2996146975 524 RESILIENCE = 392767087 525 RECOVERY = 1943323491 526 DISCIPLINE = 1735777505 527 INTELLECT = 144602215 528 STRENGTH = 4244567218 529 LIGHT_POWER = 1935470627
An Enum for Destiny 2 character stats.
633@typing.final 634class TierType(int, Enum): 635 """An enum for a Destiny 2 item tier type.""" 636 637 UNKNOWN = 0 638 CURRENCY = 1 639 BASIC = 2 640 COMMON = 3 641 RARE = 4 642 SUPERIOR = 5 643 EXOTIC = 6
An enum for a Destiny 2 item tier type.
743@typing.final 744class TransferStatus(Flag): 745 """An enum for items transfer statuses.""" 746 747 CAN_TRANSFER = 0 748 """The item can be transferred.""" 749 IS_EQUIPPED = 1 750 """You can't transfer since the item is equipped.""" 751 NOT_TRASNFERRABLE = 2 752 """This item can not be transferred.""" 753 COULD_BE_TRANSFERRED = 4 754 """You can trasnfer the item. But the place you're trying to put it at has no space for it."""
An enum for items transfer statuses.
You can trasnfer the item. But the place you're trying to put it at has no space for it.
33class UndefinedType: 34 """An `UNDEFINED` type.""" 35 36 __instance: typing.Optional[UndefinedType] = None 37 38 def __bool__(self) -> typing.Literal[False]: 39 return False 40 41 def __int__(self) -> typing.Literal[0]: 42 return 0 43 44 def __repr__(self) -> str: 45 return "UNDEFINED" 46 47 def __str__(self) -> str: 48 return "UNDEFINED" 49 50 def __new__(cls) -> UndefinedType: 51 if cls.__instance is None: 52 o = super().__new__(cls) 53 cls.__instance = o 54 return cls.__instance
An UNDEFINED type.
75@typing.final 76class ValueUIStyle(int, enums.Enum): 77 AUTOMATIC = 0 78 FRACTION = 1 79 CHECK_BOX = 2 80 PERCENTAGE = 3 81 DATETIME = 4 82 FRACTION_FLOAT = 5 83 INTEGER = 6 84 TIME_DURATION = 7 85 HIDDEN = 8 86 MULTIPLIER = 9 87 GREEN_PIPS = 10 88 RED_PIPS = 11 89 EXPLICIT_PERCENTAGE = 12 90 RAW_FLOAT = 13 91 LEVEL_AND_REWARD = 14
An enumeration.
245@typing.final 246class Vendor(int, Enum): 247 """An Enum for all available vendors in Destiny 2.""" 248 249 ZAVALA = 69482069 250 XUR = 2190858386 251 BANSHE = 672118013 252 SPIDER = 863940356 253 SHAXX = 3603221665 254 KADI = 529635856 255 """Postmaster exo.""" 256 YUNA = 1796504621 257 """Asia servers only.""" 258 EVERVERSE = 3361454721 259 AMANDA = 460529231 260 """Amanda holiday""" 261 CROW = 3611983588 262 HAWTHORNE = 3347378076 263 ADA1 = 350061650 264 DRIFTER = 248695599 265 IKORA = 1976548992 266 SAINT = 765357505 267 """Saint-14""" 268 ERIS_MORN = 1616085565 269 SHAW_HAWN = 1816541247 270 """COSMODROME Guy""" 271 VARIKS = 2531198101
An Enum for all available vendors in Destiny 2.
532@typing.final 533class WeaponType(int, Enum): 534 """Enums for The three Destiny Weapon Types""" 535 536 NONE = 0 537 KINETIC = 1498876634 538 ENERGY = 2465295065 539 POWER = 953998645
Enums for The three Destiny Weapon Types
586def into_iter( 587 iterable: collections.Iterable[Item], 588) -> FlatIterator[Item]: 589 """Transform an iterable into an flat iterator. 590 591 Example 592 ------- 593 ```py 594 sequence = [1,2,3] 595 for item in aiobungie.into_iter(sequence).reversed(): 596 print(item) 597 # 3 598 # 2 599 # 1 600 ``` 601 602 Parameters 603 ---------- 604 iterable: `typing.Iterable[Item]` 605 The iterable to convert. 606 607 Raises 608 ------ 609 `StopIteration` 610 If no elements are left in the iterator. 611 """ 612 return FlatIterator(iterable)
Transform an iterable into an flat iterator.
Example
sequence = [1,2,3]
for item in aiobungie.into_iter(sequence).reversed():
print(item)
# 3
# 2
# 1
Parameters
- iterable (
typing.Iterable[Item]): The iterable to convert.
Raises
StopIteration: If no elements are left in the iterator.
229async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError: 230 """Generates and raise exceptions on error responses.""" 231 232 # Not a JSON response, raise immediately. 233 234 # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized 235 # request with a dummy access token. I can't really do anything about this.. 236 if response.content_type != "application/json": 237 return HTTPError( 238 f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}", 239 http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE, 240 ) 241 242 body = await response.json() 243 message: str = body.get("Message", "UNDEFINED_MESSAGE") 244 error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS") 245 message_data: dict[str, str] = body.get("MessageData", {}) 246 throttle_seconds: int = body.get("ThrottleSeconds", 0) 247 error_code: int = body.get("ErrorCode", 0) 248 249 # Standard HTTP status. 250 if response.status == http.HTTPStatus.NOT_FOUND: 251 return NotFound( 252 message=message, 253 error_code=error_code, 254 throttle_seconds=throttle_seconds, 255 url=str(response.real_url), 256 body=body, 257 headers=response.headers, 258 error_status=error_status, 259 message_data=message_data, 260 ) 261 262 elif response.status == http.HTTPStatus.FORBIDDEN: 263 return Forbidden( 264 message=message, 265 error_code=error_code, 266 throttle_seconds=throttle_seconds, 267 url=str(response.real_url), 268 body=body, 269 headers=response.headers, 270 error_status=error_status, 271 message_data=message_data, 272 ) 273 274 elif response.status == http.HTTPStatus.UNAUTHORIZED: 275 return Unauthorized( 276 message=message, 277 error_code=error_code, 278 throttle_seconds=throttle_seconds, 279 url=str(response.real_url), 280 body=body, 281 headers=response.headers, 282 error_status=error_status, 283 message_data=message_data, 284 ) 285 286 elif response.status == http.HTTPStatus.BAD_REQUEST: 287 # Membership needs to be alone. 288 if error_status == "InvalidParameters": 289 return MembershipTypeError( 290 message=message, 291 body=body, 292 headers=response.headers, 293 url=str(response.url), 294 membership_type=message_data["membershipType"], 295 required_membership=message_data["membershipInfo.membershipType"], 296 membership_id=int(message_data["membershipId"]), 297 ) 298 return BadRequest( 299 message=message, 300 body=body, 301 headers=response.headers, 302 url=str(response.url), 303 ) 304 305 status = http.HTTPStatus(response.status) 306 307 if 400 <= status < 500: 308 return ResponseError( 309 message=message, 310 error_code=error_code, 311 throttle_seconds=throttle_seconds, 312 url=str(response.real_url), 313 body=body, 314 headers=response.headers, 315 error_status=error_status, 316 message_data=message_data, 317 http_status=status, 318 ) 319 320 # Need to self handle ~5xx errors 321 elif 500 <= status < 600: 322 # No API key or method requires OAuth2 most likely. 323 if error_status in { 324 "ApiKeyMissingFromRequest", 325 "WebAuthRequired", 326 "ApiInvalidOrExpiredKey", 327 "AuthenticationInvalid", 328 "AuthorizationCodeInvalid", 329 }: 330 return Unauthorized( 331 message=message, 332 error_code=error_code, 333 throttle_seconds=throttle_seconds, 334 url=str(response.real_url), 335 body=body, 336 headers=response.headers, 337 error_status=error_status, 338 message_data=message_data, 339 ) 340 341 # Anything contains not found. 342 elif ( 343 "NotFound" in error_status or error_status == "UserCannotFindRequestedUser" 344 ): 345 return NotFound( 346 message=message, 347 error_code=error_code, 348 throttle_seconds=throttle_seconds, 349 url=str(response.real_url), 350 body=body, 351 headers=response.headers, 352 error_status=error_status, 353 message_data=message_data, 354 ) 355 356 # Other 5xx errors. 357 else: 358 return InternalServerError( 359 message=message, 360 error_code=error_code, 361 throttle_seconds=throttle_seconds, 362 url=str(response.real_url), 363 body=body, 364 headers=response.headers, 365 error_status=error_status, 366 message_data=message_data, 367 http_status=status, 368 ) 369 # Something else. 370 else: 371 return HTTPException( 372 message=message, 373 error_code=error_code, 374 throttle_seconds=throttle_seconds, 375 url=str(response.real_url), 376 body=body, 377 headers=response.headers, 378 error_status=error_status, 379 message_data=message_data, 380 http_status=status, 381 )
Generates and raise exceptions on error responses.
384def stringify_http_message(headers: collections.Mapping[str, str]) -> str: 385 return ( 386 "{ \n" 387 + "\n".join( # noqa: W503 388 f"{f' {key}'}: {value}" 389 if key not in ("Authorization", "X-API-KEY") 390 else f" {key}: HIDDEN_TOKEN" 391 for key, value in headers.items() 392 ) 393 + "\n}" # noqa: W503 394 )